Nested curly braces with AngularJS - angularjs

I'm currently working on a project using angular-translate. The goal for me is to create a translation map which allows a developer to change an object model without breaking the translation.
For example, say I have an order saved inside my scope:
$scope.order = {
numberOfItems: 5,
// ...
};
And a translation map with a property displaying the number of items:
var translationsEN = {
itemsNumber: "{{numberOfitems}} item(s)",
// ...
};
var translationsFR = {
itemsNumber: "{{numberOfItems}} article(s)",
// ...
};
With this map, I could easily do this:
{{'itemsNumber' | translate:order}}
But if a developer would like to change the name of the numberOfItems property, he will have to change the translation map too, which is pretty fastidious... So, I've changed my translation map for this:
var translationsEN = {
itemsNumber: "{{number}} item(s)",
// ...
};
var translationsFR = {
itemsNumber: "{{number}} article(s)",
// ...
};
Now, a developer just have to transmit a simple object with the necessary values, like this:
<span translate="order.misc.itemsNumber"
translate-values="{ number:{{order.numberOfItems}} }">
</span>
But, as you can see, I'm no longer using filters but directives. I can't find any way to do something like this:
{{'order.misc.itemsNumber' | translate:'{ number:{{order.numberOfItems}} }'}}
This doesn't work either:
{{'order.misc.itemsNumber' | translate:'{ number:order.numberOfItems }'}}
Is there any solution allowing me to use filters or should I just use directives?

Try without the quotes:
{{'order.misc.itemsNumber' | translate: {number: order.numberOfItems}}}

Related

Pass variable to component view to be used as filter

I've build a simple component that allows passing a filter as a parameter, and I'm trying to use that parameter in the component view, but I don't know how. It gets passed as a string so it's treated as a string in the component view and thus not working.
Basically it looks something like this:
<number-compare value="some.value" filter="currency"/>
And in the component view:
<span> {{ numCompCtrl.value | numCompCtrl.value.filter }} </span>
But that doesn't work because it gets interpreted as {{ 10 | "currency" }}
I've tried to handle it in the controller instead, and apply the filter there but it gets really messy when the filter needs multiple parameters so the easiest thing by far would be if I could get the simple way working.
Is it possible?
Actually, I just discovered that I had already solved this previously with another filter as a workaround 🙈
(function() {
'use strict';
angular
.module('core')
.filter('dynamic', dynamic);
dynamic.$inject = ['$interpolate'];
function dynamic($interpolate) {
return function(value, name) {
if (!name) {
return value;
}
var result = $interpolate('{{ value | ' + name + ' }}');
return result({ value: value });
};
}
})();
And used like this:
{{ numCompCtrl.value | dynamic: numCompCtrl.value.filter }}

How to translate the content of an attribute with angular-translate

in my mongo schema i have an enum with predefined types:
let MeterSchema = new Schema({
[...]
type: {
type: String,
enum: ['Prepayment', 'TimeOfDay', 'PowerExport']
},
[...]
}
What i want is to display this value internationalized with i18n files on my angular view.
I looked at the Variale replacement of angular translate (https://angular-translate.github.io/docs/#/guide/06_variable-replacement), but could not figure it out how do it properly with this.
At the moment i translate it that way:
View
<div class="md-summary">{{vm.getMeterType(meter) | translate}}</div>
Controller
public getMeterType(meter): String {
return 'app.masterData.meters.type.' + meter.type;
}
But i think there has to be a better way to this.
The answer is actually pretty simple:
<div class="md-summary">{{'app.masterData.meters.type.' + meter.type | translate}}</div>
I don't know why i didn't use string concatenation in the first place.

Adding filter to ng-repeat

I'm currently making a front-end with Angular.
I have a JSON file like following:
{
"groups": [
group1: {
"part":1
},
group2: {
"part":2
}
]
}
And I have lists like following:
<li ng-class="{active: section >= {{group.number}}}" ng-bind="group.title" ng-repeat="group in groups" ></li>
Let's say there are 100 groups in my JSON file. If I want to only show groups with "part":1, how do I add this filter in ng-repeat?
You can pass an object to filter with the key/value you want to filter on:
ng-repeat="group in groups | filter:{part:1}"
try this
ng-repeat="group in groups | filter:{'part': 1}:true"
from official documentation
In HTML Template Binding
{{ filter_expression | filter : expression :
comparator}}
for comparator value if its true
true: A shorthand for function(actual, expected) { return
angular.equals(actual, expected)}. This is essentially strict
comparison of expected and actual.
this gives you the exact match
Consider also passing a function rather than Object into filter (which may work this time, but not all things are easily expressible in a readable fashion directly in the view):
ng-repeat="group in groups | filter:functionOnScope"
The | pipe operates on the thing to the left groups, so filter is a function whose first argument receives groups and whose subsequent arguments appear after the :. You could visualize a | b:c:d | e as e(b(a,c,d)) - once I realized that I used filters more for simple things.
So the second argument filter receives is a predicate (function that takes in something and returns true or false to operate on each element - like a SQL WHERE clause) inside groups. Filters are super useful - if you have quick logic or transformations you want to do in the view (and you don't need to test it) then they can make your controllers and directives more succinct. (So instead of ng-if="collection[collection.length - 1].length > 0" you could write ng-if="collection | last | some", which is much more readable.)
If you have complicated logic, it may be better to put in a controller or directive instead of the view (this is also easier to unit test that way if you care about it) - if it's in the view you need something like PhantomJS at a minimum to emulate the DOM. Assuming you bound some dynamicallySelectedPart on the $scope to 1, 2, etc. maybe as an ng-model on a <select /> so the user can select it, then you can just write this to keep it dynamically up-to-date.
$scope.functionOnScope = function (elementInGroups) {
// Maybe do a check like:
// if ($scope.dynamicallySelectedPart === elementInGroups.part) {
return true;
// }
// Some other logic...
return false;
};
Your JSON looks malformed in that you have an array with key-value pairs.
Below is some code that should work. I am using the Controller ViewAs syntax.
HTML
<div ng-app="MyApp">
<div ng-controller="MyController as me">
{{me.greeting}}
<ul>
<li ng-repeat="group in me.groups | filter:{'part': 1}:true">
{{group}}
</li>
</ul>
</div>
JS
var myApp = angular.module('MyApp',[]);
myApp.controller('MyController', function() {
this.greeting = 'Hola!';
this.groups = [ {id: 'group1', "part":1 }, {id: 'group2', "part":2 } ];
});
Code Pen Here

AngularJS - Can't use filter to set variable in view

I'm using a filter to calculate values, but then I want to access them later on.
Here's a snippet of my code:
app.controller('CreateProposalCtrl', function() {
$scope.EstimatedCostItem = [];
});
-
app.filter('EstimatedValue', function() {
return function(input, arguments) {
...blah blah calculations
return calculations;
};
});
I'm not sure how the HTML should be presented.
This displays exactly what I want..BUT I need it to set a variable so I can access it somewhere else..
<span ng-repeat="foo in bar">
{{ Type.JobTypeID | EstimatedValue: form }}
</span>
I've tried:
<span ng-model="EstimatedCostItem[Type.JobTypeID]" ng-bind="Type.JobTypeID | EstimatedValue: form"></span>
And:
<span ng-bind="EstimatedCostItem[Type.JobTypeID]">{{ Type.JobTypeID | EstimatedValue: form }}</span>
And:
<span ng-init="EstimatedCostItem[Type.JobTypeID] = (Type.JobTypeID | EstimatedValue: form)"></span>
Nothing seems to set a variable. I'm stumped :(
The filter syntax only works within specific Angular expressions. Expressions that use plain JavaScript cannot use the foo | bar filter syntax, as it's not valid JavaScript.
What you could do is use $filter:
var value = $filter('EstimatedValue')(foo);
Remember to inject $filter into your controller.
With that said, this probably isn't the best use of a filter. Why not create a scope function that calculates and stores the value? Something like:
$scope.EstimatedValue = function(foo) {
var value = doSomeCalculations();
// store for usage elsewhere
this.estimatedValuesCache[foo] = val;
return val;
};

How can I pass a parameter to an ng-click function?

I have a function in my controller that looks like the following:
AngularJS:
$scope.toggleClass = function(class){
$scope.class = !$scope.class;
}
I want to keep it general by passing the name of the class that I want to toggle:
<div class="myClass">stuff</div>
<div ng-click="toggleClass(myClass)"></div>
But myClass is not being passed to the angular function. How can I get this to work? The above code works if I write it like this:
$scope.toggleClass = function(){
$scope.myClass = !$scope.myClass;
}
But, this is obviously not general. I don't want to hard-code in the class named myClass.
In the function
$scope.toggleClass = function(class){
$scope.class = !$scope.class;
}
$scope.class doesn't have anything to do with the paramter class. It's literally a property on $scope called class. If you want to access the property on $scope that is identified by the variable class, you'll need to use the array-style accessor:
$scope.toggleClass = function(class){
$scope[class] = !$scope[class];
}
Note that this is not Angular specific; this is just how JavaScript works. Take the following example:
> var obj = { a: 1, b: 2 }
> var a = 'b'
> obj.a
1
> obj[a] // the same as saying: obj['b']
2
Also, the code
<div ng-click="toggleClass(myClass)"></div>
makes the assumption that there is a variable on your scope, e.g. $scope.myClass that evaluates to a string that has the name of the property you want to access. If you literally want to pass in the string myClass, you'd need
<div ng-click="toggleClass('myClass')"></div>
The example doesn't make it super clear which you're looking for (since there is a class named myClass on the top div).

Resources