I have the following template for directive item in angular. Item contains property type in it's scope. Based on this type I need to render different template.
<item ng-repeat="myItem in items track by myItem.id">
<div ng-switch="::myItem.type">
<div ng-switch-when="type1">
Some complex html with a couple of ng-if and ng-include
</div>
<div ng-switch-when="type2">
Some complex html with a couple of ng-if and ng-include
</div>
<div ng-switch-when="type3">
Some complex html with a couple of ng-if and ng-include
</div>
<div ng-switch-when="type4">
Some complex html with a couple of ng-if and ng-include
</div>
<div ng-switch-when="type5">
Some complex html with a couple of ng-if and ng-include
</div>
<div ng-switch-when="type6">
Some complex html with a couple of ng-if and ng-include
</div>
</div>
</item>
I'd like to rework every ng-switch-when in the standalone directive, and improve performance of ng-repeat (right now it has to make ng-include and set innerHTML for every item and it's a heavy operation for the browser even for list of 50 items).
So my questions are:
how to rework ng-switch-when into standalone directives
how to improve performance of the ng-repeat in this case
Update:
The question related to the AngularJS: Parse HTML events in timeline it's one the reasons why I would like to optimize current structure.
added missed track by
a lot of ng-if and ng-include statements is needed because every widget that represented by ng-switch-when has it's own logic and will be rendered based on some other parameters of myItem.
The problem also that I need to fully rebuild this list of item by some user action.
BTW:
In react I can do something like:
render: function() {
//it's for two items, but can be extended for any number of templates
var child = this.props.type === 'Type A' ? <TemplateA /> : <TemplateB />;
return child;
}
I don't know why you need a lot of IF statements, and why you want use directives for that, but i can help you with advice for ng-repeat.
Use track by $index in ng-repeat to improve performance. And check articles about Angular performance, like this: 11 Tips to Improve AngularJS Performance
Also, if you have interface with a lot of elements which need to render, may be you should look in ReactJS which is faster for rendering.
Related
I have an ng repeat repeating data. - Some of data.image (src) is null, and those with src=null are not to be repeated.
I solved it with a simple ng-if.
<div ng-repeat="data in data">
<div class="ImageContainer">
<img ng-src="{{::data.image}}" ng-if="data.image != null" />
</div>
<div class="LabelContainer">
<p>
{{::data.label}}
</p>
<div>
<div>
but from debugging I noticed this cost me around 500 watchers. Any obvious way to accomplish what im trying without the ng-if or a major JS vanilla function ?
You could filter the list in your controller so you have a method which returns all of the items in the collection where the image property isn't null and bind your repeat to that function.
You can apply one way binding on ng-if that way you can reduce few more watchers.
I agreed with #DoctorMick, filter will reduce number for loop, watchers and it will be fast as well. But if you have some other data along with image and you want to show that data then it will not solve your purpose.
I have the following fiddle setup to demonstrate what I am experiencing.
http://jsfiddle.net/BjornJohnson/ndxnG/25/
My controller uses these objects: page => rows => columns => pieces. A page has rows. A row has columns. A column has pieces.
There is a custom directive ("piece"). The point of the directive is to be able to provide different types of HTML elements based on the "type" of the piece (so-called dynamic templating).
I keep running into problems when I remove pieces from a column. I am modifying the model, but it's not reflected in the view. It works when the ng-repeat is on a wrapper, but not on the custom directive itself, so I think something is clashing with the ng-repeat directive.
I apologize in advance for using all caps, but I CANNOT USE A WRAPPER DIV FOR THE NG-REPEAT :)
The code in question is both in the view and the directive.
Here's part of the custom directive:
var template = templates[scope.piece.key];
var replacement = $($compile(template)(scope));
element.replaceWith(replacement);
Here's part of the view:
<div ng-repeat="column in row.data.columns" ng-class="column.data.clss">
<!-- notice wrapper for ng-repeat - THIS VIOLATES MY REQUIREMENTS -->
<div ng-repeat="piece in column.data.pieces">
<piece></piece>
</div>
</div>
versus...
<div ng-repeat="column in row.data.columns" ng-class="column.data.clss">
<!-- notice ng-repeat on custom directive -->
<piece ng-repeat="piece in column.data.pieces"></piece>
</div>
I'm currently making a switch from Knockout to Angular. The main problem I'm having right now is in transferring my original templates to something Angular will recognise.
Specifically, here's a bit of code I'm having trouble transferring:
<!-- ko template: { name: 'SquareTempl', data: Squares[5] } --><!-- /ko -->
In Knockout, this will attach Squares[5] to SquareTempl, so that when the template gets rendered, it does so using the members within Squares[5](or whatever data that gets attached).
I need to repeat the process for Squares[0]~Squares[11]. I can't use ng-repeat though since I won't be iterating through them in numerical order.
Ideally, it would be nice if I could do something along the lines of
<td class="Square" id="five" ng-include src="'SquareTempl.html'" ng-data="Squares[5]">
Any ideas?
Here's a JSFiddle I've written to outline a failed attempt I've tried using ng-model.
http://jsfiddle.net/fZz3W/9/
Two things: First, you can make ng-data be available by implementing it yourself YourApp.directive("ngData", function() {}) Secondly, do you need the HTML to be part of another file? An easy way to accomplish what you're looking for in Angular is with ng-repeat like:
<td ng-repeat="item in Square">
<div>{{item.name}}</div>
</td>
When the Square array is updated an additional post will be made.
Review your modified JSFiddle: http://jsfiddle.net/TdWMF/1/
So this is mostly a hack to achieve what you want, until I can offer you a better solution:
Second update using mixed order ng-repeat: http://jsfiddle.net/TdWMF/3/
Basically:
<div ng-repeat="index in [4, 2, 0, 3, 1]">
square index: {{index}}<br />
square: {{Squares[index]}}
</div>
Pretty ugly, and non-ideal, I know. I'd also recommend performing the order array generate in a function and then doing: ng-repeat="index in displayOrder(Squares)"
I want to bind tag name to variable in AngularJs. Direct way doesn't work:
<div ng-app ng-init="list=['pre', 'div', 'em']">
Check the list: {{list}}
<div data-ng-repeat="item in list">
{{item}}: <{{item}}>content</{{item}}>
</div>
</div>
How to do it right?
You're going to want to make a Directive and use the $compile service module.
Angular template system works on DOM tree, not on strings, so template must be valid HTML and usage of {{}} for tagname is impossible. We can write own directive for it (see Max answer) or if here is small set of options it can be more easy to use ng-include and set of templates for options.
Is there a way to dynamically inject partial templates (and have it work the same way in both Ruby & Javascript)? Basically, I'm trying to render different types of objects in a list.
The best I can come up with is this:
<div class="items">
{{#items}}
<div class="item">
{{#is_message}}
{{> message}}
{{/is_message}}
{{#is_picture}}
{{> picture}}
{{/is_picture}}
</div>
{{/items}}
</div>
I'm not super-psyched about this approach.
Is there a better way?
Also note that the different types of models for the views can have non-similar fields. I suppose I could always go to the lowest common denominator and have the data hash contain the html, however I would rather use the mustache templates.
I did the same thing you did, and for each property type i needed a dynamic partial, I just set a dynamic variable in the js data model that's being rendered in the template...
eval("this.set({is_" + this.get("propertyType") + ": true})")
or
this["is_" + propertyType] = true
At least I don't have to manually set the 'is_whatever' variable...
It would be cool if mustache.js or ICanHaz.js had some clever syntax for dynamic properties inside of mustache tags... maybe something like this:
{{>{{message}} }}