Is there a difference between [class]="'success'" and class="success" in Angular? - javascript

In Angular is there a difference between [class]="'success'" and class="success"?
So for example:
<li class="success">...</li>
or
<li [class]="'success'">...</li>
IIUC the latter will cause the replacement of the former if both are used at the same time, so I'm trying to better understand why we would not just use the first one?

The first one (class) is just a html class attribute.
The latter ([class]) is actually an angular binding, meaning that whatever is in it will be parsed just like any other angular binding (you can put angular/javascript expressions in it).
You are fine to use class if the classes doesn't need to change. Use [class] if you plan to change them. You can even mix them up, like:
<li class="success" [class.active]="true">...</li>

Related

Proper way to delete ng-repeat item from child directive

So, I got the following generic structure:
<list-item ng-repeat="item in collection">
<remove-item>
<a ng-click="remove()">delete</a><!-- this is inside the view.html -->
</remove-item>
</list-item>
I need a proper way to, when triggered, the remove() function remove the full parent of the clicked .
I got this working calling scope.parent().parent()....remove() on the directive, but it is a shitty way to do that =P
Is there a better way? (sure there is).
Please, don't mind this lame question. I am new at AngularJs, and I am having a hard time trying to solve that. =(
Thank you in advance.
There are a few ways to avoid the $scope.$parent.$parent ... problem in Angular. If you are using scopes, you should put any callback or property that you want children to access in a sub-property of the scope. For example, in the parent directive, use $scope.api.remove = function() {...} rather than $scope.remove = function() {...}. Then you can call it in child directive like so:
<list-item ng-repeat="item in collection">
<remove-item>
<!-- remove() is bound to $scope.api rather than directly to $scope -->
<a ng-click="api.remove()">delete</a>
</remove-item>
</list-item>
The other way to do this would be to refactor your code to use controllers rather than scopes. This seems to have become the preferred way of doing things, and it is how Angular 2 works. This pattern is made especially easy by the new component feature in v1.5.0. I won't give a detailed example, but you can read more about this pattern here, and more about components here.

Is it bad form to use html class attribute as a variable

I am wondering if the html class attribute should only be used for styling. Is there any drawback to using the class attribute as a variable. The W3 spec http://www.w3.org/TR/html5/dom.html#classes does not specify one way or another but, all examples and training point in the direction of styling only for multiple objects.
In my case I want to use the class attribute as variable that matches the key value in a object array. For example in my Javascript code I have an object that has a number of key/value pairs. On my web app I have a number of save buttons. When a save button is clicked I grab the parents class attribute value and use it as the key for the object to know which value to change. The class attribute on the parent has not other value than to let me know which key value pair to change in my object
While I'm sure it's possible to use classes that way, it's certainly not their intended purpose. html has data attributes that provide the functionality you want, for example
<button data-key="some value" name="" id="">click me</button>
You can then get that value (onClick if you like) and use it as a key for your object/data structure. Theres a good overview here
While it is not bad, it neither is best practice.
You can, instead of using the class attribute, define explicit data attributes. Using the class attribute would mean that you could not use several classes (because that would be a weird key to search for in an object, right?).
For instance:
<div class="any classes you like" data-mykey="searchforthiskey">
<button></button>
</div>
In jQuery:
$('button').click(function() {
var key = $(this).closest('div').attr('data-mykey');
});
From a functional perspective, there's no reason to NOT use the class attribute to store information about that element. You can access a class attribute as easily as you can a data attribute.
From a standards perspective, it is probably better to use a data attribute. Why? Well, if you are the only person working on your front-end, no big deal. If you are one of many on a team of front-end developers, who works specifically on the javascript side of things, you may run into a conflict with another front-end developer who works on the HTML/CSS side of things. They may remove a class from the element, not realizing that its also being used as your javascript hook into that element. In that case, you're better off creating your own data attribute, which then makes it clear that this attribute is probably data related and won't be molested by someone just trying to fix the styling of that element.

ng-repeat with includes: best performant way?

I am facing a performance issue with Angular (Ionic), and I'd like to know which would be the most performant way to solve this problem.
I get a list of objects from a service that I have to show in my app:
$scope.objectList = [
{
id: 123456,
name: "abcdefg",
state: [1|2|3|4|5|6|7|8...],
....
},
....
];
The list won't never have more than 20-25 objects.
The problem is that the elements in the list, although they are of the same type, they have to be shown in a quite different way. I have a different template for each posible state an object can be in.
I am using ng-repeat this way to show the list. The list won't change so I can use one way binding.
<div ng-repeat="obj in ::objectList track by obj.id">
....
</div>
Inside this ng-repeat I have to include the presentation template of each object, which changes depending on the object state.
I have tried different solutions but don'f find one that improves substantialy the rendering performance.
For example, I've tried this but I'm not sure that binding a function to ng-include is very performant.
HTML:
<div ng-repeat="obj in ::objects track by obj.id">
<div ng-include="getTemplateToInclude(obj)"></div>
</div>
JS:
$scope.getTemplateToInclude = function(obj){
if(obj.state === 1){
return "tmpls/template-a.html";
}else if(obj.state === 2){
return "tmpls/template-b.html";
}
....
};
Any suggestion of how to deal with this problem? Whicch would be the best way to include this different templates in the same list?
Do I have to use the one way binding notation(::) in the included templates or it's enough with the one used in the ng-repeat?
thanks in advance
I haven't used the one-way binding template syntax (::) so I won't speak to that. But based on your comments and original question, I think the best approach would be something along these lines:
create a single item renderer template that will process your repeater items
continue to use track by syntax in your repeater in order to recycle the item renderers
based on the item's type, use a combination of ng-show & ng-hide to display the correct children nested in your template.
<!-- item renderer template.html -->
<div>
<div ng-show="item.type == 'foo'"></div>
<div ng-show="item.type == 'bar'"></div>
<div ng-show="item.type == 'baz'"></div>
</div>
Creating a single template combined with track by in the repeater will reuse the DOM elements, negating the need to pull them from the DOM and then insert new ones.
Using ng-show or ng-hide vs. ng-if is based on the same idea as above. You are toggling the visibility of the DOM elements rather than destroying/creating them.
The reason I argue for this is that in nearly all performance-related tweaking, reusing or recycling objects are usually faster than destroying and then recreating new objects. This is certainly true of Javascript, and while I've yet to test that theory in DOM manipulation, I would bet it too is true. I'm making an educated guess but since you are using the Ionic framework, this should benefit mobile performance as well,
Just keep in mind, given the various permutations of what you could be showing and the number of rows of data, you might only see marginal performance gains. Depending on the number of bindings inside your template, you might reach a point where the performance penalty for Angular's digest cycle to complete is the same as the performance gains from recycling your DOM elements.

Using class with angular vs ng-class while using a mixed expression

I have a div that I want to give a dynamic class with AngularJS.
The div is withing an ng-repeat statement where lang.prefix is first en then sv
Using the following code works and sets the class to i-flag-en than i-flag-sv, but is it correct?
<div class="float-left flag i-flag-{{lang.prefix}}"></div>
I know there exist a ng-class directive which can be used to dynamically set the class of an element with AngularJS.
I think I read somewhere in a book, that the normal class directive not should be used to set the class property dynamically with AngularJS because of the way Angular manipulates the dom.
However, the following code does not work:
<div class="float-left flag" ng-class="i-flag-{{lang.prefix}}"></div>
and I rather want to set the class in this way instead of creating another scope variable.
Is it bad practice to use the class attribute with AngularJS to dynamically set the class? Does it work all the time even if it would be bad practice?
The book you have mentioned may have talked about the problems of using ng-class and class {{}} interpolations together wherein updates in the interpolation removes the ng-class classes, this problem has already been resolved, reference. Thus, using interpolation within class attributes is totally fine, and does not break good practice because both has its own quirks.
Your usage of ng-class however is incorrect, you have to concatenate the literal string value with your scope string variable:
<div class="float-left flag" ng-class="'i-flag-' + lang.prefix"></div>
but I think it is much preferable to use your first example instead:
<div class="float-left flag i-flag-{{lang.prefix}}"></div>

angular js input bind value

I have an input like this :
<input ng-model="mysearch.myfield" id="myid"/>
that is bound to a filter
<table><tr ng-repeat="row in list|filter:mysearch">...</tr></table>
If I modify the input value in the GUI, it works perfectly, but if I try to modify its value via javascript/jquery
$("#myid").val("newvalue")
The input value is updated but the mysearch.myfield is not modified
Actually, I have a list that appears on user actions (it does not exist on page load):
<li onclick="changeTheInputValue('newvalue1')">newvalue1</li>
<li onclick="changeTheInputValue('newvalue2')">newvalue2</li>
...
with
function changeTheInputValue(v) {
$("#myid").val(v);
}
And it does not work when I click on an "li" (the input value is updated, ut the mysearch.myfield is not modified)
I also tried
<li ng-click="mysearch.myfield = 'newvalue1'">newvalue1</li>
<li ng-click="mysearch.myfield = 'newvalue2'">newvalue2</li>
...
but it does not work :(
Any idea ?
Thanks,
any javascript executing outside the angulars event loop won't be efective in angular untill you apply it. in order to do that you need to get the relevant scope and $apply the changes, since is not clear, how and why you are modifying the value outside the angular scope there is nothing much i can say except you could do something like
function changeTheInputValue(v) {
$("#myid").val(v);
angular.element($("#myid")).scope().$apply();
}
that should let angular know about the changes, how ever this is a bad design if using angular. there are far better ways to accomplish this same thing w/o having mixed execution scopes. (angular/the rest);
You are modifying the value of the input "#myid" using direct DOM manipulation. AngularJS is not aware of this. If you want both the html and the value of mysearch.myfield to update correctly, you must do so by modifying the mysearch.myfield property directly, either in a controller or via an ng-model binding or something similar.
The main reason this isn't working for you has to do with how AngularJS modifies the DOM. When you use jQuery to modify the DOM, you are circumventing angular. Angular has no way of knowing if you have changed something in the DOM except if you do it directly through Angular itself. In particular, if you are curious, read about the $compile and $digest services.
Hope this helps shed some light on the subject!

Categories