this.$el.html vs this.$el.append - javascript

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.

Related

Refresh ng-repeat even nothing has changed

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.

Callback when ngRepeat/ngIf mutates DOM

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.

How to reload angularjs scope data without rerendering bound view

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

KnockoutJs v2.3.0 : "cannot apply bindings multiple times to the same element"

Problem:
In an existing application, I'm adding a new feature which uses knockout to display a grid and some additional information. I load some of the data at the start and prepare subscriptions which load other data using ajax, create viewmodel in Razor view to inject server-side variables, and then bind it (it does not matter if I pass html node or not, I have same problem).
Upon page load, "cannot apply bindings multiple times to the same element" error appears in console, and all of the html elements which use if, with or template bindings are empty.
The only occurrences of "applyBindings" in entire project are in my view, and in knockout source. Debugging shows that it is called twice, both times from $(document).ready
When I remove apply bindings from code, and call it later manually using console, it works.
Answer is already on SO: jQuery $(document).ready () fires twice
Theme of the application was moving/manipulating html elements, and tag with viewmodel initialization was inside same html view which was manipulated later. Moving to separate section which is rendered in head solved problem.

How to reduce number of DOM elements in SPA

I have a pretty complex SPA, with many tabs, views, grids, etc. Each of the elements are generated by backbone.js from a template.
Once an element is generated I want to keep a state of the element, so I cannot destroy it.
Obviously number of DOM elements with this approach is pretty high.
Is it worth the effort to de-attach a view from DOM tree once it gets hidden and re-attach it back once it gets shown?
Will backbone.js view DOM manipulation still work on de-attached element if I use $(this.el).find()?
One approach would is to let the views add/remove there element from/to the DOM. So that only views that are visible have there element attached to DOM. So you can write a view manager that call the render method of the view, passing a DOM element where the view will be rendered in. The manager can also call a stop method where he removes the views element from the DOM.

Categories

Resources