I make some dom-manipulation inside a ng-repeat. Now I want to reset my DOM to match the model where ng-repeat is looping over. How can I force AngularJS to redraw the ng-repeat content.
Apply doesn't work obviously cause no changes where made to the model.
The whole idea of ng-repeat is that it follows the model. If you want to change the content you should really change the model. As for the dom-manipulations, you should perform those within an angular component or directive and again, make it follow the model.
If you're not doing that, you pretty much might as well not use Angular at all.
If you paste some code, would be great, but anyway for example lets say we have this:
$scope.rows = [1,2,3];
<div ng-repeat="row in rows">
{{row}}
</div>
In order to redraw the same data with ng-repeat you need to somehow change the scope. You can try this after your DOM manipilation
$scope.rows = angular.copy($scope.rows);
Actually you don't need to do any special things to re bind the DOM in angular js. Angular JS supports two way data binding, so when ever your model changes, the DOM object rebinds automatically with modified contents. So all you have to do is rebind your controller variable, that will automatically updates the DOM.
Related
I have a directive that needs to execute a callback function whenever its DOM subtree is mutated (by ngIf or ngRepeat for instance).
The directive is ideally able to be easily inserted to templates I have already made, which rules out putting an ng-init. I've looked at the documentation, and neither ngRepeat or ngIf seem to have any events. Additionally, it seems that most of the browser DOM events have been depreciated as well.
I would use a watch, but I can't think of an expression that will work, as jQuery returns a new object every time and the length of .children() might be unchanged through mutation if ngRepeat removes and inserts a node in the same $digest.
Any suggestions on how to detect any DOM subtree mutation entirely from a template-less directive?
EDIT: For more detail, I have multiple tables that have rows of data inserted with ngRepeat. Whenever a row is inserted, if the table has a resize directive, I need to add CSS to it. The resize directive is general enough to go on every table without needing any input, so I would prefer to not have to add ngInits to all the ngRepeat elements.
For anyone else looking for a solution that will usually work in situations like this, Angular recompiles all the repeated elements, even if they were already present. Thus the actual DOMNode objects are different, so you can just watch a DOMNode.
The more I read (and try to test) Angular apps, I'm seeing that it is bad practice for a controller to refer to the DOM. (e.g. this blog post).
I must be missing something big, because if the controller can't access the DOM (e.g. by "regular" javascript calls like document.getElementsByClassName), then I don't understand how to do a lot of things I'd consider very basic.
Here's a contrived, simple example that has some of the same problems that my app does:
I have a directive that is simply a red box (a div with some styles applied), and uses ng-transclude. So I'd use it in my html file like <red-box>Text that goes in the red box</red-box>
A button, when clicked, changes the color of all red boxes to blue. I would have something like this in my html file: <intput type="button" value="Make Them Blue" ng-click="makeThemBlue"/>
In the controller's makeThemBlue function, I'd (for example) find all of the divs by class name, and change the class to something else which makes them blue
Now consider that my real app is much more complicated - many "boxes" consisting of nested directives, that can be dragged around, and have their positions saved. The controller reads all of the saved settings, and lays everything out according to how the user saved it.
How would I do something like either of the above examples without having the controller access the DOM?
Here are my key rules:
Directives - For solid components and for DOM manipulation.
Services - For business logic and saving state. Directives, Controllers, Services etc. should use them.
Controllers - A views helper. No business logic should be executed inside. For complicated issues use a service.
In your case a box should be a directive.
You directive will use an observable service and register for the click event.
When the click event occurs, the observer will notify all the registered directive instances that it was clicked, and you should apply to that in your directive.
You should use Directives for this purpose.
See the documentation for Directive
Angular Directives
It gives you a built in jquery like functionality to Access Dom
the link function in Directive is amazing to Manipulate Dom with the same syntax(almost) as jquery.
Further You can Maintain Chunks of Functionality By Making Services , So you can separate each login plus you have Access to Dom and can manipulate them easily
Injecting services to controller function of directive will give you to maintain code reuseability.
By having the DOM access the controller (or natively from within the directive). This is what the declarative paradigm is all about.
If your box needs to change it's color, have it read that value, or a class, or whatever you need, from a value in the controller, or in the directive itself.
In a very basic sense:
<my-directive color="getColor()"></my-directive>
I've got a small problem. I have a bootstrap tabset within an angularjs app. The tabs are partially generated from ng-repeat and contain data, that is bound to the scope.
Basically, within the controller:
$scope.data = { ... } // Loaded from a factory
Now, when I reload this data (by replacing the old one with the new one) the tabset will be rebuilt by ng-repeat and the view will automatically switch to the first tab.
Is there a way to replace the data in scope without rebuilding everything in the view?
You aren't explicit about the specific data and which of it is used in what ways.
So this will have to be a general answer:
Try to update only the bits that actually changed.
For example do not replace whole objects or arrays, but only updated properties or indices that actually changed. That way only the relevant parts of the GUI will update.
If you must replace objects, you can still help angular keep the connection between objects in the model and dom elements for ng-repeat if you use "track by" in the expression (which is possible only if the element has some unique id that you can use for that).
Another option: Use one time binding for the parts that should change only exactly once when the data is first loaded: See the section "One-time binding" in https://docs.angularjs.org/guide/expression
When data binding in Angularjs, is there a performance difference (significant or otherwise) between
<div>{{bar}}</div>
and
<div>{{foo.bar}}</div>?
What about <div>{{foo.bar.baz.qux}}</div>?
Context: I am on a team building a large Angularjs application that will potentially have a high volume of data flowing through it, and we would like to avoid the performance hit if there is one.
As i know, the re-evaluation happens within a digest.
Angular iterates through all values in the scope and checks, if the value has changed.
It doesn't look like deep nesting causes much pains there, cuz it's just checking agains the value used in the view. (as long as you dont place a watcher on this deep nested object)
But for some hints:
Don't use methods for conditions within the view:
<span data-ng-hide="someFunction()"></span>
The function will be executed on each digest this may hurt.
Don't use watchers on top of a deep object structure:
Will recursivly run through the whole thing for re-evaluation --> hurts
Use directives instead of {{}}:
Why? Example: angular-translate:
If provides a filter and a directive for the same thing.
<span>{{'WELCOME'|translate}}</span>
<span data-translate="'WELCOME'"></span>
The filter will be re-evaluated on every digest, while the directive has a watcher on that passed value and only re-evaluates, if this code does actually change.
Use data-ng-if instead of ng-Show/Hide (And since the data-ng-if is available):
ng-Show/Hide just makes the DOM elements disappear by using display:none; with css.
The hidden DOM elements will still be evaluated and the data changed, even if it's not visible.
ng-if will completely remove the DOM element, no re-evaluation for stuff within the ng-if
Is there a different between this.$el.html and this.$el.append when rendering templates? I'm totally new to js, backbone, etc. In the current project I'm working on, I see stuff like
this.$el.append(Project.Templates["template-library"](this.model))
in the outer view. In this case, this template is for a modal view. Then say the modal view has a row for each item to show in the modal view. Then for each of those rows, the template gets rendered like this:
this.$el.html(this.template({ libraries: libraries.toJSON() }));
Is there any difference between the two? And why append() should be used in certain situations, and html() in the other.
For me it really comes down to how you use your views' render method.
Some people like to use render as an extension of initialize, in that they only use it once, when the view first appears on the page, and often call it from initialize. With this style, you can safely use append without worrying about accidentally adding elements twice, because the render won't get run twice.
Alternatively you can design render to be used over and over again, whenever the view's element needs to change in some way. Backbone supports this style well, eg. this.model.on('change', this.render, this);. For this style, append would be annoying, as you'd constantly have to check whether elements already exist before append-ing them. Instead html makes more sense, because it wipes out whatever was there before.
With append a new element will be inserted into the $el, while html will change the content of the $el.
Using .append() will allow you to add or append something to already existing objects. Rather using .html(), it will change the entire object to new one.