Angular expression to check if model is array or object - angularjs

How can I check if an angular model is an array or an object? Is there a built in or do I have to write a filter isArray with Array.isArray()
{{[] | isArray}} doesn't work

You can use the angular.isArray function. It's built-in inside Angularjs.
If you want to use this function inside your template, you have to create a custom filter: http://docs.angularjs.org/tutorial/step_09
Example of what you want:
angular.module('...', []).filter('isArray', function() {
return function (input) {
return angular.isArray(input);
};
});
Then you can use the filter inside your template:
{{ myVar | isArray }}

I guess you can also add underscore/lodash to the rootScope and use it:
_ = require('lodash')
angular.module('app',[])
.run(function($rootScope){
$rootScope._ = _
})
And in the template:
<div ng-show="$root._.isArray(foo)">
<label> First element of Foo </label>
<span> {{ $root._.first(foo) }} </span>
</div>
The benefits - you have to add lodash only in one place, and it will be available everywhere. You can use many other things the same way, like Math functions for example. Just be reasonable and don't put too much javascript into expressions.

Related

Directive with ng-model Attribute Not Resolving Using $http

Trying to make a rating directive but I'm stuck at getting rating2 to work. The first rating worked because the rating1 is hardcoded within the controller. But normally I have to get the saved rating from the db, which I'm trying to do with rating2, as u can see the value is fetched but the directive is not appearing.
https://codepen.io/eldyvoon/pen/MbBNLP
<div star-rating ng-model="rating.rating1" max="10" on-rating-select="rating.rateFunction(rating)"></div>
<br>but rating2 is actually there:
{{rating.rating2}}
<star-rating ng-model="rating.rating2" readonly="rating.isReadonly"></star-rating>
Need expert of directive to help.
Initiate rating2 :
function RatingController($http) {
this.rating1 = 5;
this.rating2 = 0; //ADD THIS LINE
var self = this;
it works for me
check here
First of all, I'm not a directive expert but i'm trying to help. I think that when html is first load, the values from db not finish execute and bind into html. The best way is not using directive instead using controller to fetch data from db.
You pass a model without rating2 into your directive and the changes from the parent controller won't affect it, because variable is created afterwards. Adding a watcher in your linker on parent scope will solve the problem;
scope.$parent.$watch('', function(rating){
updateStars();
});
Other solution would be to define a starting value in your controller.
this.rating2 = 1;
Notice that it is bad design to have a scope variable for each rating. It is cleaner to have an array of ratings and you actually do not need the watcher by doing so.
https://codepen.io/hoschnok/pen/LbJPqL
angular controller
function RatingController($http) {
this.ratings = [4];
var self = this;
$http.get('https://api.myjson.com/bins/o0r69').then(function(res){
self.ratings.push(res.data.rating2);
});
}
HTML
<div ng-app="app" ng-controller="RatingController as rating" class="container">
<div ng-repeat="r in rating.ratings">
<div star-rating ng-model="r" max="10" on-rating-select="rating.rateFunction(rating)"></div>
</div>
</div>
The watcher change handler function has parameters reversed:
//INCORRECT parameters
//scope.$watch('ratingValue', function(oldValue, newValue) {
//CORRECT parameters
scope.$watch('ratingValue', function(newValue, oldValue) {
if (newValue) {
updateStars();
}
});
The first argument of the listening function should be newValue.
The DEMO on CodePen
ALSO
The ng- prefix is reserved for core directives. See AngularJS Wiki -- Best Practices
JS
scope: {
//Avoid using ng- prefix
//ratingValue: '=ngModel',
ratingValue: '=myModel',
max: '=?', // optional (default is 5)
onRatingSelect: '&?',
readonly: '=?'
},
HTML
<!-- AVOID using the ng- prefix
<star-rating ng-if='rating' ng-model="rating.rating2"
max="10" on-rating-select="rating.rateFunction(rating)">
</star-rating>
-->
<!-- INSTEAD -->
<star-rating ng-if='rating' my-model="rating.rating2"
max="10" on-rating-select="rating.rateFunction(rating)">
</star-rating>
When a custom directve uses the name ng-model for an attribute, the AngularJS framework instantiates an ngModelController. If the directive doesn't use the services of that controller, it is best not to instantiate it.

angularjs translate works only in html ?

i have used angular-translate, and it works great.
But now the problem is how can i use it in my controller functions?
normal we can use it in the html templates as {{ 'mystring' | translate }}
but i actualy want to do this:
function bla(){
var myvalue = 'mystring' | tranlate
return value;
}
and then in my html {{ value }}
As per Docs,to use filter inside controller is as follows.
$filter('filter')(array, expression, comparator)
You need to write something below
app.controller('MainCtr', ['$scope','$translate','$filter', function ($scope,$translate,$filter) {
$translate.use($scope.language.langCode);
$scope.data = $filter('translate')('Title');//where Title is language dependant
});]);
Demo to call filter inside controller
It seems you are trying to show dinamic content on your html. To achieve this you should think in other way to do it using angular-translate. I can guess you are trying to achieve this:
controller.js
$scope.mystring = 'MY_LITERAL_CODE';
inde.html
<span>{{ mystring | translate }}</span>

how to avoid double encoding with $sce

Angular $sce service seems to be encoding characters and not trusting the html. Is there an option to have the html trusted?
$scope.text = $sce.trustAsHtml('it's broken')
An example.
<p>it's working</p>
<p>{{ text }}</p>
Looks like.
it's working
it's broken
I'd rather not use ng-bind-html because it's meant to be used in a filter like the following.
{{ text | render }}
It is not the $sce that encode your html, actually nothing does that.
But when you use an interpolation {{ text }}, angular will detect that and replace it with a correct value via textNode.nodeValue, not something like innerHTML. Therefore, your ' will be treated as a normal text, not an encoded HTML entity.
That's why the ng-bind-html exists, and nothing prevent you from using the filter inside the ng-bind-html expression.
<div ng-bind-html="text | render | trustAsHtml"></div>
Example filters:
.filter('render', function () {
return function (value) {
return value + '!';
};
})
.filter('trustAsHtml', function ($sce) {
return function (value) {
return $sce.trustAsHtml(value);
};
})
Example Plunker: http://plnkr.co/edit/F8OQvoSzOR06TPepc2Fo?p=preview

How to use a dynamic value with ngClass

I'm trying to apply a class name that's the same as a scope variable.
For example:
<div ng-class="{item.name : item.name}">
So that the value of item.name is added to the class. This doesn't seem to do anything though. Any suggestions on how to do this?
Thanks!
EDIT:
This is actually being done within a select, using ng-options. For example:
<select ng-options="c.code as c.name for c in countries"></select>
Now, I want to apply a class name that has the value of c.code
I found the following directive, which seems to work, but not with interpolation of the value:
angular.module('directives.app').directive('optionsClass', ['$parse', function ($parse) {
'use strict';
return {
require: 'select',
link: function(scope, elem, attrs, ngSelect) {
// get the source for the items array that populates the select.
var optionsSourceStr = attrs.ngOptions.split(' ').pop(),
// use $parse to get a function from the options-class attribute
// that you can use to evaluate later.
getOptionsClass = $parse(attrs.optionsClass);
scope.$watch(optionsSourceStr, function(items) {
// when the options source changes loop through its items.
angular.forEach(items, function(item, index) {
// evaluate against the item to get a mapping object for
// for your classes.
var classes = getOptionsClass(item),
// also get the option you're going to need. This can be found
// by looking for the option with the appropriate index in the
// value attribute.
option = elem.find('option[value=' + index + ']');
// now loop through the key/value pairs in the mapping object
// and apply the classes that evaluated to be truthy.
angular.forEach(classes, function(add, className) {
if(add) {
angular.element(option).addClass(className);
}
});
});
});
}
};
}]);
Better later than never.
<div ng-class="{'{{item.name}}' : item.condition}">
yes. ' and {{ for classname.
I'm on angular 1.5.5 and none of these solutions worked for me.
It is possible to use the array and map syntax at once though it's only shown in the last example here
<div ng-class="[item.name, {'other-name' : item.condition}]">
Simply using the variable should be sufficient:
<div ng-class="item.name" />
This is also documented in the official documentation.
I think you missed the concept.
A conditional css class looks like this:
<div ng-class="{'<css_class_name>': <bool_condition>}">
And I dont think you want:
<div ng-class="{'true': true}">
You probally want to use:
<div ng-class="item.name"></div>
Angularjs Apply class with condition:
<div ng-class="{true:'class1',false:'class2'}[condition]" >
This can be useful in some cases:
HTML:
<div ng-class="getCssClass()"></div>
JS:
$scope.getCssClass = function () {
return { item.name: item.name };
};

How to use a filter in javascript instead of the Html

I'm using AngularJS and it's great.
I can't find it in the Documentation - What is the equivalent in Javascript to this AngularJS expression:
<div>{{ (myList| filter:mySearch).length }}</div>
Thanks for the help.
It's on Angular's filter documentation:
In HTML Template Binding
{{ filter_expression | filter:expression }}
In JavaScript
$filter('filter')(array, expression)
In your case, it would look something like $filter('filter')(myList, mySearch).
As an alternative syntax you can also inject a filter directly, without going through the $filter service. For example to inject filter filter to your controller you could write:
MyCtrl = function($scope, filterFilter) {
$scope.filtered = filterFilter(myArray, expression);
}
A question very similar to How to use a filter in a controller?
In your html
<input ng-model="search">
<div ng-repeat="thing in things | filter:searchResults"></div>
In your JS
$scope.$watch('search', function (newValue, oldValue) {
var searchResults = filterFilter($scope.things, $scope.search);
});

Resources