I am trying to integrate angular into an older existing web-app. I have a few places where large portions of the page are re-rendered from rails partials via ajax requests.
Once a portion of the page is re-rendered in this way, any existing angular bindings (e.g.: ng-click) are lost and buttons no longer work. Is there any way to manually tell angular to re-check for binding attributes?
If you are loading some HTML and need angular to process it you'll need to run $compile on the HTML code for angular to parse for directives and you'll need to attach a scope to the returned link function. Show some code. If you are simply getting new data you can use $http which will automatically call $digest for you or else you can call $digest from some other callback to notify angular it needs to update the display.
Related
I'm adding a chat feature to my site using angularJS and signalR. It is very barebones right now...My angular controller maintains an array of chat logs, and
prints them out with:
<div ng-repeat="log in vm.logs">{{log.sender}}: {{log.msg}}</div>
All the wiring works, and I have verified via console.log() that messages are being received instantly. However, it seems the DOM is not updated until I interact with the page (such as hovering over another component that has an angular action attached to it). I'm not sure if it's an issue with angular or just javascript. Any ideas?
I've seen this on sites like Facebook, and I thought it was by design but it looks like it's a browser/javascript thing.
Use $timeout and wrap your vm.logs scope array with a function. $timeout automatically calls the angulars digest cycle and your dom should start getting updated.
I have an Angular SPA but in it I'm using some non-angular library (Medium Editor [ME from now on] to be exact). I created a directive for ME so if I add a contenteditable element on my views, ME get's instantiated and works properly. So that's not a problem.
The problem is that I also created a special ME extension that requires to make web requests to my server in order to insert correct markup into ME's editable element. But to make these requests it requires some view-model's data and also communicate it back:
it needs to read and set (when undefined) my view model ID
it needs to constantly manipulate some other view model value in order for my SPA to know that it's still processing so other processes get postponed
I thought I'd simply include input type="hidden" ng-model="..." on my page and change its value and trigger input event so Angular would update its model. Hidden input of course doesn't work. So I changed it to input type="text" class="hidden" and keep the functionality.
This does work, but it doesn't seem to be the proper way of doing things as it's hackish. And this mainly works for model value exchange (get/set). How about if I would have to call some controller function? Is that even remotely possible?
I don't want to make ME's extension to rely in any way on Angular library as it has to be purely ME extension and should be reused in non-Angular SPAs (maybe some other lib SPA or just pure simple DHTML web app). But I would like to make it usable in SPAs as well as ME can easily be used to manipulate some element's markup that can be set to view model through a directive.
What it the proper way of communicating with Angular app from external libs that aren't native to Angular?
Additional info
Basically I want to have 4 functions in my custom extension that should somehow access (and manipulate) my Angular view model:
getReferenceId() and setReferenceId(id)
incrementPending() and decrementPending()
Pending counter could be exposed publicly and accessed by my Angular SPA, so it wouldn't process data while extension is still doing its own stuff. But SPA doesn't have any authority over when to set reference ID so it would correctly be read by the extension...
This is usually solved by wrapping external plugins (or their parts) in ng services and directives. You don't need the input tag, just put the data on scope and after changing from non-ng code call $scope.$digest. If you need to watch for data change to trigger something in external library, you can use either ng-change or $scope.$watch.
During the debugging of my angularjs application, I found a lot of parse html events in the dev tools.
The timeline says that this event is invoked by jQuery.extend.buildFragment and it's hard for me to understand, what directive invokes parse html.
How can I detect, what exactly causes parse html events? Probably the reason could be in the ng-repeat, but I'm not sure.
These events slow down $scope.$apply as well.
Every partial html in angular will trigger Parse HTML event, like ng-includes, ng-repeats, directives, and $digest cycles.
Also using jQuery will give you a lot of overhead for initalize jquery instances. jQuery or jQlite buildFragment is called when you or directives or angular call element.html('something tags'), which in turn write to innerHTML which cause parse HTML event in browser and angular walk those children to find more directives and compile those until its complete.
To minimize those, you need to batch process those, but nature of angular will be hard to do directly. May be you can try to use one-time binding syntax :: in angular 1.3+ or make less watchers, so angular won't have to parse html again and again.
I am loading an angular 'template' using ajax. This template renders a bootstrap modal form when I call $compile ... this works, everything fine here. But what I need is support of embedding controllers within this lazy loaded 'template' (Preferably I want to handle this client side so on server side everything can just look normal).
The thing is when I use ng-controller inside this template and define a function controller inside a script tag it fails. It tells me it cant find the controller function. I understand why this is happening, the script has not yet been initialized. I am just looking for a solution. How can I make the embedded script tags initialize first? Should I extract them, inject them somewhere and then compile the remainder? Or is there a more elegant way?
Lets have look in AngularJS documentation and show the integration with the browser event loop.
So you can see that AngularJS have its own event loop, which consists of three phases: compile, digest and apply.
When you call compile it will only loads the html markup and insert it. You should call apply also.
With apply you will set the execution scope. This will register an watcher that listens to changes.
While profiling a large AngularJS app, I started tracking $templateCache.
https://docs.angularjs.org/api/ng/service/$templateCache
What is this object? Does it store the partials as they are stored on disk or the final rendered HTML from the route?
I've added some code like this to my controller to make sure it's not persisting anything:
$scope.$on('$destroy', function cleanup() {
$templateCache.removeAll();
});
EDIT: the reason I am looking into this is that a single (not every) controller is loading a large partial with several loops inside of it, depending on User input it could be about 100 input fields with large <select> statements and many custom directives. The client is requesting it be this way and I want to make sure that all of this is getting disposed during routing.
To clarify the question: $templateCache is only storing the partials as they appear on disk, no routing or rendering information is being stored?
By default, while loading templates, Angular looks inside $templateCache and fetches templates over XHR when it cannot find them locally in its $templateCache.
When the XHR request is slow or our template is large enough, it can seriously negatively impact end users’ experience .
instead of fetching templates XHR, we can fake the template cache loading by wrapping it into a JavaScript file and shipp the JavaScript file along with the rest of the application.
Sample :
angular.module('myApp')
.run(['$templateCache', function($templateCache) {
$templateCache.put('xyz.html', ...);
}]);
So, unless you are very much sure to remove the cached templates form $templateCache, don't do that.
If I remember correctly, it's a object where partials are saved. When making a request to any html file (through routing, directives or include) , angular first looks into $templateCache, and if required file doesn't exist, it will make a request for it and will put it in the cache. But if it does exists, it is taken from there. So if you are using your directive 100 times per page, it will only make one request for your directive file, or if you navigate back and forth your app, it won't request files that were already loaded.
Does it make sense to add $templateCache.removeAll(); on each controller? Only if it's really small application, otherwise I suggest not messing around with it..