Replace values from json - angularjs

I display data from a json.
I want replace values from an other (for translation).
It's like :
<li ng-repeat="childrens in data.children track by $index">
<a>{{childrens.type}}</a>
</li>
In 'type' I can have "QUOTE", "BILL" or "DEPOSIT"...
And I want replace this value with the translation.
But I'm beginner in angular, and i work on json for the first time as well, what's the better way to do this ?
I tried to use the fonction replace() in my controller but that doesnt work :
if($scope.children.type =='QUOTE'){
$scope.children.type = $scope.children.type.replace('Facture');
}
Thanks for your help guys :)

You can do this:
<li ng-repeat="childrens in data.children track by $index">
<a>{{mapObject[childrens.type].text}}</a>
</li>
In Controller you can use javascript map
$scope.mapObject = {
"QUOTE":{
"text":"Facture"
}
}

Related

AngularJS : filter item in ng-repeat without using filter

I would like to filter my item store in database, but I don't want to use filter like this :
<li ng-repeat="post in posts | filter: { etat: 'enCours' } ">
This line filter all the posts where etat = 'enCours', but this cause me several problem cause I have several ng-repeat and I can't use $index.
I would like to do something like this :
<li ng-repeat="post in postsEnCours">
With using this function :
This line give me all the post store in my database
$scope.posts= Posts.query();
$scope.postsEnCours = $scope.posts.filter(function(item, index) {
return item.etat === 'enCours';
})
But nothing appears do you know why ?
You shouldn't be depended on ng-repeat's $index .
If you use isolate directive or directive with scope : true in ng-repeat, you won't find $index correctly.
Posts.query() may have callback. If it has callback then you have to put your filter inside it's callback's method.

Efficient way to bind Json to Html?

I am trying to find out a better way to bind my json data to my html .
Json:
$scope.json = { 'one': { 'name': 'level1', 'two': { 'name': 'level2', 'three': { 'name': 'level3' } } } };
Html:
<div ng-controller="myController" >
<div ng-repeat="data in json"> -- (1)
<b>{{data.name}}</b>
<div ng-repeat="data1 in data">
<b>{{data1.name}}</b>
<div ng-repeat="data2 in data1 track by $index"><b>{{data2.name}}</b></div> -- (2)
</div>
</div>
</div>
Pointers : //marked in view
There is no array in my json data , so , is there a better way rather using ng-repeat (sort of traditional for) . Anything like with binding in knockout or templates (i'm not sure How) .
I see there are no duplicates in my json but still to compromise the error i have been using track by $index at the final inner div(if exclude final div i see no error) .
1: There is no array in my json data , so , is there a better way
rather using ng-repeat (sort of traditional for) . Anything like with
binding in knockout or templates (i'm not sure How) .
There is no way to use JSON object for ng-repeat but you can directly use JSON object using . operator for property.
Check below code
<div ng-controller="myController" >
<div>
<b>{{json.one.name}}</b>
<b>{{json.one.two.name}}</b>
<b>{{json.one.two.three.name}}</b>
</div>
</div>
2 : I see there are no duplicates in my json but still to compromise
the error i have been using track by $index at the final inner div(if
exclude final div i see no error).
The reason for error is because you are trying to get index of JSON object which doesn't has index.

calling a function from ng-repeat with the object from the current scope

I'm trying to call a function (from a non event element) from a ng-repeat to feed an array of data to an autocomplete element (using https://github.com/JustGoscha/allmighty-autocomplete).
It's to generate a kind of logic system :
type(listbox) | comparator (eg:>=) (listbox) | value(autocomplete)
And several of those object can be listed on a webpage to get some complex logic
type=value && type2>value3 || ...
Depending on type and comparator, values are different.
The code so far (simplified):
<div class="comparator" ng-repeat="comp in container.comparators">
<select ng-model="comp.type"><option ng-repeat="i in type_options" value="{{i.value}}" ng-selected="{{i.value==comp.type}}">{{i.label}}</option></select>
<select ng-model="comp.comparator"><option ng-repeat="i in comp_options|filter:typeMatch(comp)" value="{{i.value}}" ng-selected="{{i.value==comp.comparator}}">{{i.label}}</option></select>
<autocomplete class="autocomplete" data="" attr-placeholder="Entrez votre valeur" click-activation="true" on-type="**updateValue**" ng-model="comp.value"></autocomplete>
</div>
updateValue is the function to call, but i need to know the current object (comp from the ng-repeat) on which i am to send the right array of value.
I tryed to send an existing array to avoid "digest loop"
$scope.updateValue = function(crit){
for(var i=0;i
I also tryed to do a function that return a function that return the array :DDDDD :
$scope.updateValue = function(crit){
return function(value/*not used*/){
for(var i=0;i<$scope.comp_options.length;i++) {
if($scope.comp_options[i].value===crit.comparator){
$scope.value_elements=$scope.comp_options[i].info;
break;
}
}
return $scope.value_elements;
};
};
Replacing the autocomplete object with :
if I console.log(comp), I see that I can get my object, but I get a digest loop ...
Is there a way to know the object of the "line" I was called from ?
Thx (i'm a total newbie in angular, but so far, i've been unable to find how to retrieve that information ... is that even possible :) ?).
Access it using $index ? Example below. You can then use the index to access it
<tr ng-repeat="user in uc.users track by $index">
<td>{{user.id}}</td>
<td>{{user.first_name}}</td>
<td>{{user.last_name}}</td>
<td>{{user.email}}</td>
<td>{{user.department}}</td>
<button ng-click="uc.open(user.id, $index);">Open</button>
</tr>

Generate new $index for array items per specific key:value in Angular

Please be patient if I don't understand something and need clarification as I'm still new to Angular, and please simplify explanations for an Angular newbie if you can, thanks!
I am working on a table display of data drawn from a database and using ng-repeat to generate it as something like "item in results.items". There are three "types" of item, let's just call them "title", "action" and "comment". Since results.items is the array, the $index goes by item placement in the whole array regardless of type.
What I want to do is be able to number only ONE type of item, item.type=='action'. Obviously if I just put
<td ng-show="item.type=='action'">{{$index}}</td>
it is going to go by the original array index, so instead of having my data with each 'action' numbered 1, 2, 3, etc. in sequence, I end up with them numbered as they fall in the array, something like: 5, 8, 9, 12, 15, 16, 22.
Can anyone clue me in on a straightforward way to set up the generation of a new $index (such as '$actionIndex') in my controller that will re-index only the items that are of type=='action'? Ideally I'd like to be able to designate a $scope function for this in my controller and then just call it with ng-model or something.
I know this inquiry is lacking in the code sampling department -- it's a little awkward in this case for me because I'm still pretty new to Angular and I can't just copy the actual code due to company NDA rules. Thanks for bearing with me and any assistance you can lend.
EDIT/UPDATE:
After reviewing the solution offered by pixelbits, I am wondering whether what I should do here instead is create a new associated id # for each item where "type==action" and just increment it with each successive item where "type==action"?
I don't want to filter items with "type!=action" out of the display entirely. Right now it is using an inclusive ng-repeat and sorting so that other types of "item", where applicable, appear in proper order under this type (item==action) to explain/enhance it. This means I have <tr> set up with the ng-repeat="item in items" and then <span> tags within the td cells per row to ng-show depending on type. I'm not seeing how to logically use a different ng-repeat based on type. I just want to reindex all type==action items and display that new index numeral instead of that of the larger default array "items" itself.
Still working on it ...
Here is a code snippet from the template to illustrate:
<tbody>
<tr ng-repeat="item in items" ng-class="{title: item.type=='title', action: item.type=='action', comment: item.type=='comment'}">
<td class="grid-2">
<span ng-show="item.type=='action'">{{$index}}</span>
<span ng-show="item.type!='action'"> </span>
</td>
<td class="action-text grid-8">
<span class="title regular-item" ng-show="item.type=='title'">
<h3>{{item.field}}</h3>
</span>
<span class="action regular-item" ng-show="item.type=='action'">{{item.field}}</span>
<span class="comment" ng-show="item.type=='comment'"><i>Comment by: {{item.author}}<br />{{item.field}}</i></span>
</td>
<td class="grid-2">
<span ng-show="item.type=='action'" class="timestamp" data-toggle="tooltip" data-original-title="{{item._created | date: 'hh:mm:ss a'}}">{{item._created | date: 'hh:mm:ss a'}}</span>
<span ng-show="item.type!='action'"> </span>
</td>
</tr>
</tbody>
So as you can see I have the general ng-repeat and then the template lays it out according to type. "Action" is a pretty "important" type as it has special displays the others do not.
You could implement a $watch handler:
JS
app.controller('ctrl', function($scope, $filter) {
$scope.result = ...;
$scope.actionList = [];
$scope.$watchCollection('result.items', function(newArr) {
$scope.actionList = $filter('filter')(newArr, { type: 'action' }, true);
});
});
HTML
<ul>
<li ng-repeat="item in actionList">{{ $index }}</li>
</ul>
After unsuccessfully trying what pixelbits suggested here, in the end I went back to the Service and plugged in a counter there which I could place in my template.
Relevant snippet:
}, function(response) {
var items = response.data;
var i = 1;
_.each(items, function(item) {
if (item.type == 'action') {
item.counter = i++;
}
});
callback(response.data);
});
And in the template:
<span ng-show="item.type=='action'">{{item.counter}}.</span>
One of my constant issues is "over-thinking" a problem (making it more complicated in my mind than it needs to be) and this was no exception! Hopefully this will help someone else in the future as well.

Mustache - How to detect array is not empty?

I want to implement the following logic with Mustache:
{{#if users.length > 0}}
<ul>
{{#users}}
<li>{{.}}</li>
{{/users}}
</ul>
{{/if}}
// eg. data = { users: ['Tom', 'Jerry'] }
Should I modify the users structure to meet the need? For example:
{{#hasUsers}}
<ul>
{{#users}}
<li>{{.}}</li>
{{/users}}
</ul>
{{/hasUsers}}
// eg. data = { hasUsers: true, users: ['Tom', 'Jerry'] }
Sorry, this may be too late. But I had similar requirement and found a better way to do this:
{{#users.length}}
<ul>
{{#users}}
<li>{{.}}</li>
{{/users}}
</ul>
{{/users.length}}
{{^users.length}}
<p>No Users</p>
{{/users.length}}
Working sample here: http://jsfiddle.net/eSvdb/
Using {{#users.length}} works great if you want the inner statement to repeat for every element of the array, but if you only want a statement to only run once, you can use:
{{#users.0}}
...
{{/users.0}}
{{^users.0}}
...
{{/users.0}}
I'm using chevron for Python. Since {{#users.length}} is implementation-dependent as described in previous answers, and doesn't work for me in Chevron, I return an object in my code which only contains the list if the list is non-empty. Presumably this technique would work for other languages too.
users = ["user1", "user2", "userN"]
user_obj = {"user_list": users} if len(users) > 0 else {}
template = """
{{#users}}
<ul>
{{#user_list}}
<li>{{.}}</li>
{{/user_list}}
</ul>
{{/users}}
"""
chevron.render(template, {"users": user_obj})

Resources