How can I sucessfully do this?
ng-class="{'a':x, 'b':::y}"
Notice how I'm trying to bind only once with "y" but not with "x"
I also tried using multiple ng-class directives, like this:
<div ng-class="{'a':x}" ng-class="::{'b':y}"></div>
but doesn't work either.
The problem is that you can only specify one-time binding syntax :: at the beginning of the expression. Here your expression is an object literal and using :: before the second key value results in an invalid syntax. You would have to split them up and probably place one section in the class expression (There is no point using 2 ng-class directives).
Example:
ng-class="{'a':x}" class="someclass {{::{true:'b'}[y]}}"
Documentation
An expression that starts with :: is considered a one-time expression. ....
.a {
color: green;
}
.b {
color: blue;
}
.a.b {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<div ng-app>
<div ng-class="{'a':x}" class="{{::{true:'b'}[y]}}">Test</div>
X->
<input type="checkbox" ng-model="x">Y->
<input type="checkbox" ng-model="y">
</div>
Note: One time binding will keep the watch until it gets an non undefined value for the bound property. If the property value is available at the time view renders (i.e not asyncronous) you could just do
<div ng-class="{'a':x}" class="{{::y ? 'b': ''}}">Test</div>
as well.
Related
E.g
I have an array of text like $scope.array = [{text:'abc'}, {text:'pqr'}, {text:'xyz'}];
Now along with ng-repeat I want to change the colour of the text of any particular element of the array. how to achieve it?
IMO, we've multiple options to achieve that.
If you want to change single property then you can use ng-style but let say if you want to manipulate multiple properties then its preferable to use ng-class.
ng-style
The ngStyle directive allows you to set CSS style on an HTML element conditionally.
<div ng-repeat="contact in jsonContacts">
<span ng-style="{'color':($first ?'red':'blue')}">{{data.row}}</span>
</div>
ng-class
The ngClass directive allows you to dynamically set CSS classes on an HTML element by databinding an expression that represents all classes to be added.
<div ng-repeat="i in array" ng-class="{'green': $last, 'blue': $first}">
{{i.text}}
</div>
FYI,
The ngRepeat directive instantiates a template once per item from a collection. Each template instance gets its own scope, where the given loop variable is set to the current collection item, and $index is set to the item index or key.
$first boolean true if the repeated element is first in the iterator.
$middle boolean true if the repeated element is between the first and last in the iterator.
$last boolean true if the repeated element is last in the iterator.
Official documentations
ngRepeat
ngClass
ngStyle
Hope this helps you :)
var app = angular.module('app', []);
app.controller('homeCtrl', function($scope) {
$scope.array = [{text:'abc'}, {text:'pqr'}, {text:'xyz'}];
});
.green
{
color: green;
}
.blue
{
color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="homeCtrl">
<h3>ng-style used</h3>
<div ng-repeat="i in array" ng-style="{'color':($first ?'red':'blue')}">{{i.text}}</div>
<br/>
<h3>ng-class used</h3>
<div ng-repeat="i in array" ng-class="{'green': $last, 'blue': $first}">{{i.text}}</div>
</div>
</div>
</div>
You can achieve this by using directives such as ngClass or ngStyle, to apply classes or style changes conditionally to certain HTML elements.
Let's assume you're listing your $scope.array elements:
<ul>
<li ng-repeat="element in array">{{element.text}}</li>
</ul>
You could add a class called .red (that would change the text color to red) to an element if text === 'pqr', but changing the above example to:
<ul>
<li ng-repeat="element in array" ng-class="{'red': element.text === 'pqr'}">{{element.text}}</li>
</ul>
Similarly you can also use the directive ng-style to apply a style directly, avoiding new classes.
Since you're using an ngRepeat, you can also its iterator $index to apply classes/styles on more advanced cases such as first/last element, element index is odd/even, etc...
For more examples and clarifications, please check the official documentation for both directives:
https://docs.angularjs.org/api/ng/directive/ngClass
https://docs.angularjs.org/api/ng/directive/ngStyle
You can use ng-class or ng-style, even including an auxiliar function in your controller to calculate that style.
<div ng-repeat="item in array" ng-class="calculateClass(item)" ng-style="calculateStyle(item)">
<!-- more stuff -->
</div>
EDIT
For your case it could be useful depending on what logic you want to apply to do something like
$scope.calculateStyle = function(item){
var color;
// Some logic to define color
return {
'color': color
}
}
My question is in regard of best practice / preferred readability in Angular 1.X with ng-show and ng-hide.
When using ng-hide and ng-show, is it advised to stick to one and to alternate the value I am evaluating or should i alternate between the two in order to keep the value in the expression the same?
See the following examples. Is one preferred over the other and if so why?
Assume that there are only two states, sportSelected can be Hockey or Football that is it, so there are two states.
Using only ng-show and switching the value
<div class="col-xs-4" ng-show="vm.sportSelected=='hockey'">
NJ Devils
</div>
<div class="col-xs-4" ng-show="vm.sportSelected=='football'">
NY Jets
</div>
<div class="col-xs-4" ng-show="vm.sportSelected=='football'">
NY Giants
</div>
Alternating between ng-show and ng-hide to keep the value the same
<div class="col-xs-4" ng-show="vm.isHockeySelected">
NJ Devils
</div>
<div class="col-xs-4" ng-hide="vm.isHockeySelected">
NY Jets
</div>
<div class="col-xs-4" ng-hide="vm.isHockeySelected">
NY Giants
</div>
The top seems more clear to me but it could just be due to poor method and variable names. I am looking through the angular documentation and I cant seem to arrive at what the preferred result is. Is one preferred over the other?
Edit: Flagged this to be closed, I realized this is pretty opinion based like tabs vs spaces even though I think one solution has benefits over the other
ng-hide and ng-show both work in different ways. They are essentially CSS classes which either hide or show the specified div, depending on how the value evaluates.
<!-- when $scope.myValue is truthy (element is visible) -->
<div ng-show="myValue"></div>
if myValue evaluates to true then the div would be visible
<!-- when $scope.myValue is falsy (element is hidden) -->
<div ng-show="myValue" class="ng-hide"></div>
however, in the second example, the div would be hidden as the class is set to that of ng-hide.
also you can run ng-show or ng-hide to check if the value evaluates to false, like so: <div ng-show="!myValue"></div>
Due to the nature of the digest cycle in Angular, these checks will be ran on page load. If you do not want the div to be shown on the page, it can be recommendable to use ng-if, rather than ng-show or ng-hide, as it will not load on the page, as opposed to simply hiding it.
In the snippet below you will see an example working for both ng-hide and ng-show, using the value of the ng-model value response of the input checkbox 'checked'. Which gives a boolean response.
When it is clicked on, the value for 'checked' evaluates to true. When it is unclicked, the value evaluates to false. When the ng-model evaluates to false, it shows the ng-hide div, when the ng-model evalutes to true, it shows the ng-show div.
Further reading here: Angular ng-show documentation
#import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
.animate-show {
line-height: 20px;
opacity: 1;
padding: 10px;
border: 1px solid black;
background: white;
}
.animate-show.ng-hide-add, .animate-show.ng-hide-remove {
transition: all linear 0.5s;
}
.animate-show.ng-hide {
line-height: 0;
opacity: 0;
padding: 0 10px;
}
.check-element {
padding: 10px;
border: 1px solid black;
background: white;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-ng-show-production</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-animate.js"></script>
</head>
<body ng-app="ngAnimate">
Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
<div>
Show:
<div class="check-element animate-show" ng-show="checked">
<span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
</div>
</div>
<div>
Hide:
<div class="check-element animate-show" ng-hide="checked">
<span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
</div>
</div>
</body>
</html>
<!--
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->
Whether or not you use ng-hide or ng-show should be based on how you want the page to appear by default. If you are controlling the visibility of an element that will be hidden by default and only shown after the user completes some action (like selecting a sport), then you want to use ng-show. If the element is to be shown by default and only hidden after some user action (maybe a div that says 'select a sport' that disappears once a sport is selected), then you want to use ng-hide.
Using the directives this way will contribute more toward readability than worrying about how the boolean condition itself is specified. It also has an important practical benefit. If you use ng-hide for something that is supposed to be hidden by default, you might see the element flicker each time you load the page, because in early $digest cycles before your scope can be fully evaluated, the result of that condition will be falsy, which will cause the element to appear briefly before it disappears.
You've got the right idea in the top example (looks like you have a syntax issue with the quotes though).
I have a directive template with the following code
<div class="colorpicker">
<div>Chosen color</div>
<div class="color_swatch" style="background-color: {{ngModel}}"> </div>
<div class="clearfix"></div>
<div>Standard colors</div>
<div class="color_squares">
<div ng-repeat="color in colorList">{{color.trim() == ngModel.trim()}} //does not update
<div class="color_swatch" style="background-color: {{ color }};"></div>
</div>
</div>
<div class="clearfix"></div>
In the directive, I update the ngmodel using the below code to the color that was clicked - the div next to "chosen color" is updated with the selected color.
But, the expression "{{color.trim() == ngModel.trim()}}" always amounts to false.
{{color.trim() == ngModel.trim()}}
I have debugged the code and the values are exactly the same.
What I am missing?
This is probably because your variable is precisely named 'ngModel' see that article for more explanation : http://zcourts.com/2013/05/31/angularjs-if-you-dont-have-a-dot-youre-doing-it-wrong/
To resume this article : never use raw fields use always a dot. So in your scope change
$scope.ngModel
By
$scope.data.ngModel
And in your html change ngModel by data.ngModel.
When using dot you may have some undefined error, this is because you have to initialize the object :
$scope.data={};
Of course you can jsut rename your variable, but you may still have a problem with others directives.
I solved this by removing curly braces around color and using ng-style
<div class="color_swatch" id="colorpicker_selected_color" ng-style="{'background-color': selectedColor}" > </div>
<p ng-repeat="row in matrix">
<span ng-repeat="column in row">
<input type="text" style="width: 20px; text-align: center;" ng-model="column" ng-change="{{column = }}">
</span>
</p>
And on my controller:
$scope.matrix = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
I have little piece of code and I want that little text input box to be associated with matrix[i][u]. I know I can use ng-model= to make the text box be associated with a certain variable.
However, I want it to go both ways - changing the variable will change the text box value and changing the text box value will change the variable. However, when I have ng-model on an input text box I can't seem to edit its value, as it'll always "reset" to its default.
I know I can use ng-change but I made the middle line this:
<input type="text" style="width: 20px; text-align: center;" ng-model="column" ng-change="update">
And it didn't work to call the $scope.update() function. I also still can't edit the text box value.
tl;dr: How can I have a text box with an ng-model and allow editing it to edit both the text box value and the variable on ng-model.
Use it this way:
<input type="text" ng-model="matrix[$index][$parent.$index]" style="width: 20px; text-align: center;" />
Example: http://jsfiddle.net/cherniv/hcLVE/
It is not very elegant , but it is working..
Here's a directive approach which is a little more fun:
app.directive("matrix", function($compile){
return{
scope:{
ngModel:'='
},
restrict:"E",
link:function(scope, element, attributes){
var render = function(){
var template="";
scope.ngModel.forEach(function(row, r){
template+="<p>";
console.log(scope.ngModel[r]);
row.forEach(function(column, c){
template+='<span><input style="width: 20px; text-align: center;" ng-model="ngModel['+r+']['+c+']"></span>';
});
template+="</p>";
});
element.html(template);
$compile(element.contents())(scope);
}
render();
scope.$watch('ngModel', render, true);
}
}
});
which can be used <matrix ng-model="matrix"></matrix>
Just because I love directives. Running here: http://plnkr.co/edit/jI7Hi9LKXnDFBd0gXtNZ?p=preview
Use
row[$index]
as the ng:model in the input tag:
<input type="text" ng-model="row[$index]" style="width: 20px; text-align: center;" />
The reason why this works and using column does not work is this: The <input> tag will create a child scope by copying the parent scope. But column is a simple/scalar variable. Such a variable will really just be copied. Therefore you end up with a copy in ng:model which is not connected to the real variable in your matrix. This is the reason why the AngularJS people stress that you should always have something with a dot inside referenced by ng-model.
On the other hand, row is still a complex variable (Array) and not a scalar. Such a variable is "copied" by JavaScript not by creating a real copy but by just copying the reference to the data. So you end up with a second reference to the same data. And therefore row in the child-scope created by the <input> tag is still connected to the original row data in the matrix and two-way data-binding will work.
To stress this again: Never use something without a dot as ng:model. AngularJS used to have bad examples doing this on their webpage but it appears that they have mostly/all been changed. But as you can see in this example something foo[5] is also ok, because it still references a complex variable. foo["bar"] would actually be equal to foo.bar.
I am having the next problem. As you can see in my jsFiddle I am trying to use ng-bind-html-unsafe inside a template in my directive, and the attribute's value that I'm passing item{{itemColumn.field}} depends because is inside an ng-repeat. The thing is that I am using the ng-bind-html-unsafe in the columns that the attribute highlight is true, because the idea is to filter data (using the text input) and highlight the selection introduced by the user in the input. And as you can see, there is no value in those columns (because it seems that the binding is not working for some reason).
I have read about possible solutions and it one guy said that it can be fixed using $compile (which I'm actually using), so I have some time stuck in this with no idea on how to solve it.
Someone has faced something like this before? and can give me some ideas on how to solve the problem?
EDIT:
As Joachim suggests, I will provide more relevant code. In my template I have this
<td ng-repeat=\"itemColumn in gridOptions.gridColumnDefs \"
ng-show=\"itemColumn.visible | elementIsDefined : itemColumn.visible : true\" >
<div ng-switch on=\"itemColumn.highlight\"> " +
<span ng-switch-when=\"true\">
<div ng-bind-html-unsafe=\"item.{{itemColumn.field}} | highlight: {{gridOptions.searchInput}}\" ></div>
</span>
<span ng-switch-when=\"false\">{{item[itemColumn.field]}}</span>
</div>
</td>
I think my problem is related to the fact that I am trying to use a binding {{ }} inside the ng-bind-html-unsafe directive (Which i need). When the page renders, I got my div with the attributes as stated in the template, but the ng-bind-html-unsafe does not renders any HTML.
Just in case you need it, i found a way to make my issue disappear. In the link function inside my directive, I added the next functions:
scope.getValueToBind = function (item, subItem) {
return item[subItem];
};
scope.getFieldToFilter = function () {
var inputValue = scope.gridOptions.searchInput;
var returnValue = $("input[ng-model='" + inputValue + "']").val();
return returnValue;
};
And in my template I call this new functions instead of having a direct binding in the ng-bind-html-unsafe (which does not work at all with internal bindings). The functions return the values that I needed (as If i had a binding)
<td ng-repeat=\"itemColumn in gridOptions.gridColumnDefs \"
ng-show=\"itemColumn.visible | elementIsDefined : itemColumn.visible : true\" >
<div ng-switch on=\"itemColumn.highlight\">
<span ng-switch-when=\"true\"><div ng-bind-html-unsafe=\"getValueToBind(item,itemColumn.field) | highlight: getFieldToFilter()\" ></div>
</span>
<span ng-switch-when=\"false\">{{item[itemColumn.field]}}</span>
</div>
</td>
Here you can find the complete jsFiddle. If you type any letter/word that is inside the table, it will be highlighted.