I have built out an Angular directive to display a D3 visualization. I make use of $filter within the tickFormat function on my y-axis like so:
ySalesAxis = d3.svg.axis() .orient('left') .ticks(6) .scale(ySalesScale) .tickFormat(function(d) { return $filter('formatSalesValue')(d.value, 'USD'); }); The problem I'm seeing is that none of these tick labels appear when the page first loads. Indeed if I console.log($filter('formatSalesValue')(d.value, 'USD')) I get 6 undefined (since my ticks property is set to 6). However, as soon as I take an action, clicking within the brush filter for example, the tick labels appear properly formatted.
My formatSalesValue filter calls a service (async operation) because there are dozens of currencies cycling into and out of the system, details of which I retrieve from a DB. I am sure this is the reason my tick labels are undefined. What can I do to make sure these values appear right after page load? Note: I've attempted wrapping my tickFormat function in a call to scope.$apply but I get a digest already in progress error.
2 Answers
Answers 1
Axis's tickFormat method runs passed callback and uses value returned by it in sync way. That's why you get undefined on the first call, as your $filter is async.
If this async call is only for performance reasons you should make it sync and look for improvements elsewhere. Should angular watch for so many independent changes it could clog with $digest cycles.
If you make JSBin I probably could tell you more.
Answers 2
TL;DR
Try using the Angular $timeout function.
Based on your question, the issue might be any number of things, but this is what I think is the problem:
Possible issue
It think that part of the problem is that the what you're getting is happening in a weird bit of the event loop.
$timeout is useful functions because it runs when the current stack is cleared and after n milliseconds have passed, if no time to delay is given, $timeout simply runs as soon as the stack unwinds. It's a useful trick for executing asynchronous code in a single thread.
Using $timeout with 0 delay doesn't actually mean the call back will fire-off after zero milliseconds. I just gets executed after a the queue of tasks is processed. Which is when you want to update your labels.
$timeout will actually triggers a digest when it's ready to do so.
Possible solution
$timeout(function() { // Update the label with what comes back from the server }, 0, false); This is a good video explaining how the Javascript event loop works: What the heck is the event loop anyway?
0 comments:
Post a Comment