5

Ok -- so you might be thinking why would you want this but I am trying to render some HTML using ng-html-bind like so (in HAML):

#my-visualization-panel{'ng-bind-html' => 'htmlSource'}

the htmlSource has some html which renders a visualization using c3.js visualization library. The htmlSource looks something like this

<script>
  var MY_DATA = localStorage.getItem('MY_DATA');
  c3.generate({
    data: {
      columns: MY_DATA
    }
 });
</script>

So the problem is that I update the visualization by re-setting localStorage['MY_DATA']. However, while the data that MY_DATA refers to might change, the actual htmlSource does not, so the view fails to update.

Is there a way to force the view to update even if the model, ostensibly, does not?

hiroprotagonist
  • 902
  • 1
  • 11
  • 24
  • 1
    what's the point of using `ng-bind-html` at all in this instance? the appropriate way to deal with non-angular scripts in an angular context is to wrap them in a directive. – Claies Aug 31 '15 at 00:05
  • The bigger context is to allow a user to write their own c3.js code and see it visualized on the page. So need `ng-bind-html` to display and render dynamically generated html – hiroprotagonist Aug 31 '15 at 00:20

3 Answers3

3

you can use the apply method of the $scope object:

$scope.apply();

if you are still getting the digest in progress errors, you can also make use of the $timeout object that will run the function in the next digest cycle:

$timeout(function() {
    //code
});

as per your latest comment in this answer it seems to be that you are looking for the $scope.watch method. You can add a watcher in order to listen when something changes.

taxicala
  • 21,408
  • 7
  • 37
  • 66
  • hm, the problem is that the digest cycle is happening correctly -- so I get $apply already in progress errors when I use `$scope.$apply()` or `$scope.$digest()` – hiroprotagonist Aug 30 '15 at 23:54
  • I've added the $timeout approach. – taxicala Aug 31 '15 at 00:20
  • 1
    Generally, the answer I feel like I am groping for isn't how to trigger the digest cycle but to change how angular detects if something has changed. Like if there is some way to over-write its normal behavior (which is simply to call angular.equals on the model). Another digest cycle would go through all the watchers and simply return with the same answer which is that the model hasn't changed. – hiroprotagonist Aug 31 '15 at 00:21
  • now I've added the watch method maybe it's what you ate looking for. :) – taxicala Aug 31 '15 at 00:31
  • 2
    `$scope.apply()` is not an AngularJS function, use `$scope.$apply()` instead. – Quikers Sep 12 '18 at 07:50
2

I would recommend changing the HTML anyway. For example

<script>
  var MY_DATA = localStorage.getItem('MY_DATA');// 2482486284968248968 (hash of my_data, guid, or serial number)
  c3.generate({
    data: {
      columns: MY_DATA
    }
 });
</script>

This will allow your script to operate as you expect, directly, without having to do big sweeping updates or hacks. Even if you "force a refresh", if the HTML doesn't change, Angular will not re-execute your script.

Another possibility is to call localStorage.getItem('MY_DATA') in your angular controllers / directives, instead of indirectly hoping Angular will run it for you via HTML updates. That seems to be the kind of control you're looking for.

tenfour
  • 36,141
  • 15
  • 83
  • 142
  • perhaps I don't understand the problem exactly, but your code looks exactly like the code that was posted in the question? – Claies Aug 31 '15 at 00:01
  • I added a comment to the script with a key that will change along with `MY_DATA`. OP's problem is that his HTML doesn't change. This is a way to make it change. – tenfour Aug 31 '15 at 00:02
  • @tenfour added a comment into the html, which will trigger angular update -- which is my workaround but I am not a big fan of it; I just can't believe there isn't a better way in angular – hiroprotagonist Aug 31 '15 at 00:02
  • Angular's binding is for updating HTML. But what you're trying to do is run script every time `MY_DATA` changes. That's why I suggest you run `localStorage.getItem('MY_DATA')` in your model or controller then when it changes. I am guessing you have code to explicitly generate `MY_DATA` so this should be an option. Or, have Angular bind directly to `MY_DATA`. – tenfour Aug 31 '15 at 00:05
  • yea, I do exactly that. The actual object `MY_DATA` refers to will be correct and non-stale. For example, `console.log(localStorage.getItem('MY_DATA'))` returns exactly what I want and expect. The issue is purely the binding between `htmlSource` and the view. – hiroprotagonist Aug 31 '15 at 00:11
  • Also, if there were a way to bind to `MY_DATA` w/r/t to the detect changes portion of the data binding, but display `htmlSource`, it would be ideal -- but I have not been able to find how to do that in angular. – hiroprotagonist Aug 31 '15 at 00:13
1

I have spent around 2-3 hours to resolve this issue. Finally I found solution

$scope.$apply();
Hardik Gajjar
  • 1,024
  • 12
  • 27