Convert an express-like string to an expression in Angular view - angularjs

Assuming that I have an expression-like string in my scope
$scope.expressionString = 'model.key == "anything"'
I want to use this string as an expression in view, can I do that?
In view, I will have something like
<div ng-if="expressionString"></div> but of course, expressionString should be something else instead.
I appreciate any help. Cheers!

You can use $eval to evaluate your expression , there are two ways to do it in your case
Solution 1
<div ng-if="$eval(expressionString)"></div>
Solution 2
In the controller store the evaluated value of the expression like below
$scope.expressionString = $scope.$eval('model.key == "anything"')
and then in the view simply use it without using $eval in the view
<div ng-if="expressionString"></div>

I found the answer, made a parse filter to parse the string and assign it a scope
angular.module('zehitomo')
.filter('parse', function ($parse) {
return function (expression, scope) {
return $parse(expression)(scope);
};
});
And in view
ng-if="expressionString | parse:this"

You cannot use global variables (or functions) in Angular expressions. Angular expressions are just attributes, so are strings and not Javascript code.
Please see this stackoverflow answer once
Although, you can achieve it using a function instead of a variable:
$scope.expressionString = function(toCompare) {
return $scope.model.key == toCompare;
}
and in your view:
<div ng-if="expressionString('anything')"></div>

Related

AngularJS v2 is not a function?

I have a very simple piece of code to run a dynamic sortBy over my array. I am using a select with ng-model to return the correct key by which to sort. However, I can change the select once, and the orderBy works. But once I do it again, I get a very strange error
Controller
//change task sort
$scope.changeOrder = 'task_date';
$scope.changeOrder = (filterTask) => {
if (filterTask == "due") {
$scope.changeOrder = 'task_date';
} else if (filterTask == "imp") {
$scope.changeOrder = 'task_importence';
}
};
Template
<select ng-change=changeOrder(filterTask) ng-model="filterTask">
<option value="due">Due First</option>
<option value="imp">Importance</option>
</select>
<task-item ng-repeat="task in $ctrl.user.task | orderBy : changeOrder"></task-item>
Here is the error - There is nothing called "v2" in my system
Welcome to the untyped world that is JavaScript.
Your error is actually quite apparent: $scope.changeOrder becomes a function and a standard variable. Once you select a value in your select drop-down, it ceases to be a function and reverts to a standard variable. Then, you can no longer call it.
You would be wise to split this up into two variables instead. I'd recommend using $scope.orderState and $scope.changeOrder, where orderState just holds the strings and changeOrder is your function.
I think the problem is that both of your $scope variables have the same name. You try to assign a function and a value to $scope.changeOrder. Try splitting it up into two variables

concatenate string with scope variable inside ng-model

How to concatenate string with scope variable and assign it to ng-model
is there a way ti express this
ng-model="'is'+location.placeName+'Checked'"
You can use ng-bind-model instead of ng-model in this case
ng-bind-model="is{{location.placeName}}Checked"
thanks
Finally found the answer randomly in this plunker by ozkary using ng-init
HTML View
<input ng-model="isPlaceChecked" ng-init="isPlaceChecked = checkIfPlaceChecked(location.placeName)"
JS Controller
$scope.checkIfPlaceChecked = function (placeName) {
return "is" + placeName + "Checked";
}

Creating orderBy expression that runs a function in ng-repeat

I have an array of people with firstNames and lastNames. I'm want to ng-repeat through the them and then orderBy: 'lastName'. This works fine.
However, some persons in my people array only have a first name. I want to be able to order by the last name, and whenever it finds someone with a only a first name, to treat that first name as a last name, ie. the initial of the first name is alphabetised with the rest of the last names (hope that makes sense...)
Is it a case of writing a function in my controller and then calling that variable in the orderBy: expression? I've tried that and it didn't work:
Controller:
self.nameOrder = function(thisOne) {
if (thisOne.lastName == null) {
thisOne.firstName == thisOne.lastName;
}
}
View:
<p ng-repeat="name in people | orderBy: 'lastName.nameOrder()' ">{{lastName}}</p>
I'm aware the above is probably totally wrong, but I thought it better to at least show what I've been attempting so it's clearer what my intentions are :/
Any help would be appreciated. Thanks in advance.
The function is supposed to be a getter, i.e. to return a value that orderBy will use to compare all the users with each other.
Your function doesn't return anything. Moreover, you're not passing the function as argument to orderBy. The code should be:
self.nameOrder = function(thisOne) {
// return lastName, or firstName if lastName is null
return thisOne.lastName || thisOne.firstName;
}
and the html should use
ng-repeat="name in people | orderBy:vm.nameOrder"
(assuming vm is the alias used for your controller)
Maybe the problem is with:
thisOne.firstName == thisOne.lastName;
That line should be:
thisOne.firstName = thisOne.lastName;

How can I remove all string spaces in AngularJS binding?

I try to do this:
<div id="{{mystring.replace(/[\s]/g, \'\')}}"></div>
but its not working. "mystring" is an object on $scope with string like "my string is this" with spaces I want to remove from the view.
Just create a dedicated filter :
angular.module('filters.stringUtils', [])
.filter('removeSpaces', [function() {
return function(string) {
if (!angular.isString(string)) {
return string;
}
return string.replace(/[\s]/g, '');
};
}])
and call it like :
<div id="{{'hi there'| removeSpaces}}"></div>
If you simply need it in one or two places it may be easier to split and join:
$scope.boundString = 'this is a string with spaces'
with that you could do in your template:
<span>my string is: {{ boundString.split(' ').join('') }}</span>
and you would get:
my string is: thisisastringwithoutspaces
another approach that has been mentioned is the regex version ('g' is for global):
<span>my string is: {{ boundString.replace(/ /g, '') }}</span>
I guess the point is that you can do whatever you want to a string within an expression. These examples are bad convention with respect to Angular dirty-checking. In Angular, bound functions (string.replace, string.split) get evaluated differently opposed to a specified value (string, boolean) when bound to a template's expression. The result of a bound function must be evaluated before Angular knows whether or not to update the DOM. This can be costly over a large app. I would suggest using another variable to track the un-spaced value:
$scope.noSpaces = $scope.boundString.replace(/ /g, '');
HTML:
<span>{{ noSpaces }}</span>
This way, when a digest loop is triggered, Angular will check if noSpaces has changed as opposed to evaluating boundString.replace(/ /g, '').
What if you are ng-repeating? Good question.
for (var idx = 0, idx < $scope.boundIterable.length, i++) {
$scope.boundIterable[i].noSpaces = $scope.boundIterable[i].boundString.replace(/ /g, '');
}
HTML:
<ul ng-repeat="iterable in boundIterable">
<li>{{ iterable.noSpaces }}</li>
</ul>
The directive mentioned works pretty well. But if you want to remove spaces for smaller texts, you can use
.split(" ").join("")
This replaces the complete spaces unlike .replace(" ","") which replaces only the first space.
You can replace all spaces by blank by using replace():
.replace(" ","")
How about {{ string.trim() }}?
Source
You can do it by using replace():
{{mystring.replace(" ","")}}
that's it I hope so.
removeSpaces() {
originalText ="hi! here i'm";
removedSpacesText = originalText.split(" ").join("");
}

Reverse polarity of an angular.js filter

Given a filter method that returns true if some condition is met, is it possible to invoke its opposite in HTML, e.g. to use:
"item in items | filter:!AllDay"
instead of
"item in items | filter:AllDay"
? Or do you have to maintain two separate filter methods (one for false and one for true)?
As noted by ENDOH (this SO question is technically a duplicate), you can negate a filter by prepending '!' to the filter string, like this:
filter:'!'+myFilter
Note that the '!' is quoted. The documentation is not terribly clear on this, and an example there would be helpful.
shacker's answer didn't work for angular 1.0.7, so here's another way to do this:
// You can register this in your AppCtrl if you like, otherwise just use $scope.
$rootScope.not = function(func) {
return function (item) {
return !func(item);
}
};
Then you would do this:
filter:not(myFilterMethod)
filter:({day: '!'+AllDay.day})
Another option is to create a new negation filter and pipe it:
.filter('not', function() {
return function(input) {
return !input;
}
})
"item in items | filter:AllDay | filter:not"

Resources