I am a bit of a beginner, but I would like to ask a general question. AngularJS does a watch on binded variables. My question is, when I navigate and a new html template is loaded, are the old watched values removed, or do they stay in the loop?
Hello $watch is bound to a controller ,which in turn shows the data to an HTML template.
So, If you navigate to another state or url and another controller loads , then the previous controller with all the data and the $watch will be unloaded, but new ones($watch) will load from the new loaded controller(if there are any).
$watch are never removed by itself, they have to be removed manually.
You should go through $watch lifecycle : $watch life cycle
No, the $watch list is updated as per the html which is being rendered by the browser.If you change template inside the page, the browser will have to render the new expression.
I think this youtube video would help you in getting
Related
I hope someone can help me with this problem, it really drives me crazy :P I have created a Plunker in order to illustrate the problem. See the Demo here http://plnkr.co/edit/BRlDgKYlE87Bh3t53tpZ?p=preview.
My code is in the plunker.
So my problem is that I'm not able to change my scope value in a different html view that I'm in. As the Plunker show, I have two buttons in index.html; button1 and button2. When I click on button1 I want scope.test to change to "button1", and when I click on button2 it should change to "button2", this value exists in index2.html. As you can see on the console.log message, that never happen. I use rootscope, but still I'm only able to change the value if the scope exists in the same html page and not in another. Please help!
What you have coded up is not a single page application, html2 has no idea about your angular code in app.js. You need to use routing and you should be using a service to share state between the two 'pages' or views in the case of angular routing
EDIT
Take a look at this plunkr
Here you will see angular routing in action and a service that can be shared between the two controllers. When switching between the two pages, the controllers they are attached to get destroyed, so going from Page 1 to Page 2 means that contollerA no longer exists, so you need to use the service to store the state of what was clicked on from Page 1.
Hope this makes sense!
I'm learning Angular I tried to init a controller after create a new content by ajax (with jQuery, maybe it's not a good idea but just I'm starting to learning step by step.)
this is my code.
angular.module('app').controller('TestController',function($scope){
$scope.products = [{
'code': 'A-1',
'name': 'Product 01'
}];
$scope.clickTest = function(){
alert('test');
}
});
$.ajax({..})
.done(function(html){
angular.element(document).injector().invoke(function($compile){
$('#content').html(html);
var scope = $('#content').scope();
$compile($('#content').contents())(scope);
});
});
In my html I use ng-repeat but not load nothing, however when I click in
ng-click="clickTest" it works! and ng-repeat is loaded. this is my problem I need that the ng-repeat load when I load for first time.
Thanks.
Sorry for my bad english.
with jQuery, maybe it's not a good idea
Yes spot on
Now getting into your issue:- When you click on element with ng-click on the html, it works because it then runs a digest cycle and refreshes the DOM and your repeat renders. $Compile has already instantiated the controller and methods are available and attached to DOM. But there is one digest cycle that runs in angular after controller initialization, which renders data in DOM, and that does not happen in your case since you are outside angular.
You could do a scope.$digest() after compile to make sure element is rendered and digest cycle is run.
Also probably one more better thing would be to wrap it inside angularRootElement.ready function, just to make sure before the injector is accessed the element is ready, in your case enclosing it inside ajax callback saves you (the time for it to be ready) but better to have it.
Try:-
$.ajax({..})
.done(function(html){
var rootElement = angular.element(document);
rootElement.ready(function(){
rootElement.injector().invoke(function($compile){
var $content = $('#content'),
scope = $content.scope();
$content.html(html);
$compile($content.contents())(scope);
scope.$digest();
});
});
});
Sample Demo
Demo - Controller on dynamic html
Instead of getting html from the server you could create partials and templates, use routing , use angular ajax wrapper with $http etc... Well i would not suggest doing this method though - however based on your question you understand that already. There was a similar question that i answered last day
If you are not looking for a better way to do what you are doing, ignore the following.
The beauty of using frameworks like AngularJS and KnockoutJS (or many more) is that we don't have to worry about the timing of when the data loads. You just set up the bindings between the controller and the UI and once the data is loaded into the respective properties, these frameworks will take care of updating the UI for you.
I am not sure why you are trying to set up the UI using JQuery and waiting for the data to loaded first to do so but normally you will not have to do all that.
You can create a UI with ng-repeat and click bindings ,etc and make an ajax call to get the data from anywhere. Once the data is loaded, in the callback, just push the necessary data into the collection bound to the ng-repeat directive. That is all you will have to do.
I'm fairly new to angular, after using a video tutorial and reading some documentation, I decided to rebuild an old app of mine as an example with angularjs.
So this app has a table showing some data. It has a form underneath which helps you modify the data from the list. You have a button on each line which allows you to edit the line, it then fill all the fields in the form and you can then save or cancel your changes.
I made a controller to handle the list, it works fine, it gets a json from http.
I used ng-click on my edit button to trigger a function in this controller, giving it the whole object it's supposed to edit.
I made a controller to handle the form in which the edit should take place and I don't really found a 'non-hacky' way to pass the data from the list controller to the form controller.
So, my question is : what is the best practice and/or the common way to get this data from my list controller to my form controler ?
It depends how you are using the form controller. If it's being used within a template using ng-controller attribute, then this controller has access to parent scope, so you can work with list controller's data. (although note some scope-inheritance quirks solved by "dot notation", explained nicely by egghead.io: https://egghead.io/lessons/angularjs-the-dot)
If you're launching your edit form in a another url (e.g. /items/2/edit) and handle it in a routing configuration, then you can use resolve property to pass any data to the controller: $routeProvider docs.
You can pass the entire object as parameter
<row ng-repeat="theModelInRow in modelList" ng-click="edit(theModelInRow)">
if form controller isn't a nested controller of list controller on view, then you can use rootScope.
Part of the code in my controller deletes a DOM element:
MetrofficeApp.controller('EmployeesCtrl', function($scope) {
...
angular.element(deleteElem).remove();
$scope.$apply();
When I navigate away from this page using angular, and then come back to the same page where the deleted element is - the element is visible again.
What must I do besides $scope.$apply() to make the changes permanent (save DOM changes) between navigating pages?
I feel like you have a fundamental misunderstanding about the DOM. Every time you navigate back to a page, all code is re-invoked and templates are recreated. So, it is correct behavior that the DOM is created again.
My guess is that you have some underlying model that is visualized by the DOM. Rather than deleting components of the DOM, you should be deleting the part of the model that is visualized by the DOM (and pushing that change to the server). This way, the next time you navigate to the DOM, the model is consistent and the deleted item is no longer shown.
And a smaller point, but still important: controllers should not be manipulating the DOM directly. You should be creating directives for that.
You need to set some flag on the scope object which the angular js template can use to determine whether the show the dom element in question.
E.g.
// controller code
scope.shouldShowElement = some.flag;
// angular template
<div ng-show="shouldShowElement">...</div>
Angular templates have access to all the variables on the scope - if, at a later point, you do:
// controller code
scope.shouldShowElement = true;
scope.$apply();
Your template will update to reflect that change
I am having issues with something which might imply I am missing something conceptual. I am using a view with a controller which populates from a couple of different services(asynchronous). Everything works fine the FIRST time the view is navigated to. All the expected elements get populated in the controller and the dom is rendered perfectly. However, the SECOND time a user navigates to the same view, the DOM does not render all the elements. I have put breaks in the code and have confirmed that the data is populated by the service exactly as it was the first time.
I put a break on a click event so I could inspect the scope post rendering. As expected the first time it is rendered, everything is as expected. The second time, despite watching the scope variable get set, when I inspect the scope post rendering the variable is undefined!! I have looked to see the $id of the scope. I can see that the first time the $id of the scope is the same through the whole initialization and rendering. The second time the controller is initializing the same scope but when I inspect post rendering I can see that the scope has changed and is now different from the one used by the controller to initialize. I don't understand what created this second scope OR why the first scope was used to initialize the controller.
So my question(s) to the AngularJS folks are as follows:
1. Are there differences in how Angular behaves from the first and then subsequent route events to the same route. I have noticed that the pages render faster.
2. How do $digest/$apply come in to play? It won't let me call them because I get the inprog error.
3. How/approaches to debugging this? I really don't understand where to go with this. Its as if I have lost the two way bindings.
Thanks.