How can I change a value inside of ng-repeat after the repeat complete? - angularjs

I have a JSON which provides me a user's working experiences info. But country and city's are provided in a code format (TR,DE etc.)
I am using ng-repeat to pass them into html like this
<div ng-repeat="e in experiences">
<span>{{e.Name}}</span>
<span ng-init="changeCodeToFullName(e.Country)">{{vm.CountryFullName[$index]}}</span>
</div>
I am using ng-init to convert Country Code to full name. changeCodeToFullName is an angular service written by me, Is this a correct method? If it is, I can't access the dom to change CountryFullName value. I tried to access them in JS file like vm.CountryFullName[0]="TEST" but it didn't worked. I need to use e.Country variable after, therefore I can't change the original .e.Country value.
How can I access a variable inside of ng-repeat after ng-repeat completed?

How about using a custom filter:
<div ng-repeat="e in experiences">
<span>{{e.Name}}</span>
<span>{{e.Country | changeCodeToFullName}}</span>
</div>
angular.module('App').filter('changeCodeToFullName', function(YourService) {
return function(country) {
return YourService.getFullCountryName(country)
}
})
Here's an example: http://codepen.io/rustydev/pen/YWyqJB

This is one way of doing it - but this ngInit value won't be reparsed if the list updates. Why not just format the data in the JSON request response - such as:
$http.get("json.json").success(function(data) {
$scope.exeriences = data.map(function(obj) {
//Format results;
if (obj.Country == "DE") {
obj.Country = "Germany"; //etc
}
return obj;
});
});

Related

AngularJs Auto Complete Search

So this works with static data, but when I push data with a $http this autocomplete does not work. The data pushes to the empty array of airport_list but something is happening when I try to use airport_list in for the autocomplete. Not sure what is is. I can only find answers which pertain to static data.
This is updated per everyones help.
Here is the controller
app.controller('selectCtrl', function($scope, $http) {
$scope.airport_list = null;
$http({
url: 'someUrl.com',
method: 'GET'
})
.then((response) => {
angular.forEach(response.data.airports, function(value, key) {
$scope.airport_list = response.data.airports;
})
$scope.airports = $scope.airport_list;
});
$scope.selectAirport = function(string) {
$scope.airport = string;
$scope.hidelist = true;
};
})
Here is the template
<div class="control">
<div>
<input
type="text"
name="airport"
id="airport"
ng-model="airport"
ng-change="searchFor(airport)"
placeholder="From..."
/>
<div class="airport-container-dropdown" ng-hide="hidelist">
<div
class="airport-list"
ng-repeat="airport in airports"
ng-click="selectAirport(airport)"
>
{{ airport.name }}
</div>
</div>
</div>
</div>
I really would like to do this without using bootstrap typeahead.
Thank you for looking at this.
I have made changes as recommended by below answers and the $http request is feeding into the autocomplete as a whole list but searching by name does not work and clicking on name sets [object, object]
this would be the code which is specific to that functionality.
$scope.searchFor = function(string) {
$scope.hidelist = false;
const output = [];
angular.forEach($scope.airport_list, function(airport) {
if (airport[0].toLowerCase().indexOf(string.toLowerCase(airport)) >=
0) {
output.push(airport);
}
});
$scope.airports = output;
};
$scope.selectAirport = function(string) {
$scope.airport = string;
$scope.hidelist = true;
};
Try this:
$scope.airport_list = response.data.airports;
What I am seeing is that you have an array: $scope.airport_list = [];
When you make your http request, you push what I would understand to be an array of airports into that array. So you end up with your airport array from the backend at the first position of $scope.airport_list, vs. $scope.airport_list being the actual list.
For your search method, you should change the following:
In your HTML:
ng-change="searchFor(airport.name)"
In your JS:
I've renamed your function and changed the input variable to be more clear. You were passing in a full airport, but treating it as a string. You need to compare your provided airport name to that of the airports in the array. So you iterate over the array, and compare each element's name property to what you pass in.
$scope.searchFor = function(airportName) {
$scope.hidelist = false;
const output = [];
angular.forEach($scope.airport_list, function(airport) {
if (airport.name.toLowerCase() === airportName) {
output.push(airport);
}
});
$scope.airports = output;
console.log($scope.airports);
};
I have provided minimal changes to your code to implement this, however I suggest you look at this SO post to filter drop down data more appropriately.
Angularjs Filter data with dropdown
If you want to simply filter out what is displayed in the UI, you can try this in your HTML template. It will provide a text field where you supply a partial of the airport name. If at least one character is entered in that box, the list will display on the page, with the appropriate filtering applied. This will avoid having to call functions on change, having a separate array, etc.
<input type="text" name="airport" id="airport" ng-model="airportSearch.name" placeholder="From..." />
<div class="airport-container-dropdown" ng-hide="!airportSearch.name">
<div class="airport-list"
ng-repeat="airport in airport_list | filter:airportSearch"
ng-click="selectAirport(airport)">
{{ airport.name }}
</div>
</div>

angularjs ng-model in select

im stucked in a dumb problem, but i don't know how to go ahead, so i hope that someone of you can give me a help.
My problem is that i have a list of element, and i can acces for everyone of them, in which i can load the specific data of the element. In this view i can load the data from the REST backend call, and work all prettly, the problem that i have encountered is when i have to load a list with the select tag, and im working with ng-model and ng option. I want to load in that list the data selected that the element have in this moment, but when i try to put in ng-model the data that i give from the backend, that doesnt work, instead if i initialize the same element out of the service call backend that work and i can see the element selected. The service is working because i can see every value of the element, and even if i try to take the specific value i can see it if for example i put that in a paragraph. Thanks in advance.
this is where i load the list:
self.AzionePropostaLista=[
{ qsAzioneProposta:'SENSIBILIZZAZIONE', value: 'SENSIBILIZZAZIONE'},
{ qsAzioneProposta:'INIBIZIONE MANUAL ENTRY', value: 'INIBIZIONE MANUAL ENTRY'},
{ qsAzioneProposta:'INIBIZIONE BANDA', value : 'INIBIZIONE BANDA'},
{ qsAzioneProposta:'INIBIZIONE COMPLETA', value : 'INIBIZIONE COMPLETA'},
{ qsAzioneProposta:'REVOCA', value : 'REVOCA'},
{ qsAzioneProposta:'RINUNCIA', value :'RINUNCIA'},
{ qsAzioneProposta:'SBLOCCO', value :'SBLOCCO'},
{ qsAzioneProposta:'COMUNICAZIONE INTERNA', value :'COMUNICAZIONE INTERNA'},
{ qsAzioneProposta:'AUTOFIN.SOSPETTATO', value : 'AUTOFIN.SOSPETTATO'},
{ qsAzioneProposta:'VALUTATO SENZA RISCHIO', value :'VALUTATO SENZA RISCHIO'}
];
This is the data that im retriving from the backend service:
self.condition: "SENSIBILIZZAZIONE"
MerchantService.getThisAction({qs_key:$routeParams.qs_key,qs_data_proposta:formatData},function(response){
if(response.statusCode==0){
self.action = response.data;
self.condition = response.data.qsAzioneProposta; THIS DOESN'T WORK BUT I CAN SEE THAT VALUE
$log.debug("self.condition is"+self.condition);
}
else {
sweetAlert('Error','something missing or you are trying to acces an inexistent merchant', 'error');
$location.path("/home");
}
});
// self.condition = 'SENSIBILIZZAZIONE' THIS WORK
<div class="input-field col s4">
<select ng-model="$ctrl.condition" ng-options="azione.value as azione.qsAzioneProposta for azione in $ctrl.AzionePropostaLista"></select>
<label>Suggested action</label>
</div>
This is the data that i'm retriving from the backend
Your ng-model aggregates azione.value from ng-options therefore:
Change:
self.condition = response.data.qsAzioneProposta;
to:
self.condition = response.data.value;
DEMO

How does filter work in AngularJS?

I have a table generated with ng-repeat (from an objects' array).
I would like to filter it with a search text field.
Objects contained in my array has got deep properties.
I don't know why and how, but the filter is only working on email field, which is as deep as other properties.
I'm using this search form :
<input type="text" name="search" ng-model="searchText" />
...
<tr ng-repeat="x in obj | filter:searchText track by $index">
...
</tr>
plunker
EDIT :
This answer helps me to understand why it's not working.
Someone knows how I can bypass the $ verification in filter ?
I'm using $ because I'm following the Google Contact API format.
You can check the source code of ngFilter here
It is set to ignore keys starting with $ as it's a prefix used by AngularJS for public ($) and private ($$) properties.
$ is a prefix used by Angular internal properties. For technical reasons, Angular prevents you to use it. Here is a workaround to deal with $ properties names without changing your JSON object:
You can iterate in ng-repeat over Object.keys($scope.object) instead $scope.object.
Demo on JSFiddle
Since it is clear that we can change neither third party API nor AngularJS library code, we could go for modifying the object keys to not have $ in the beginning. But, since the data has so many of them at multiple level, let's do it recursively! :)
Here's how. I would remap each object in $scope.obj array to call a function:
$scope.obj = $scope.obj.map(function(cur) {
return renameKey(cur)
})
Now, inside renameKey, it would check whether it's an Array or Object using helper functions and call itself recursively while replacing the keys prepending x for the strings starting with $
function renameKey(cur) {
if(isArray(cur)) {
cur.forEach(function(obj) {
obj = renameKey(obj)
})
} else if (isObject(cur)) {
for (let key in cur) {
if(key.charAt(0) === '$') {
cur['x'+key] = cur[key];
delete cur[key];
}
cur[key] = renameKey(cur[key])
}
}
return cur
}
function isObject(obj) {
return obj && (typeof obj === "object");
}
function isArray(obj) {
return isObject(obj) && (obj instanceof Array);
}
Looks little tedius but it does work! Now, all we need to do is have x$t instead of $t in the HTML, and boom!
working plunker
email works because nested property address doesn't contain any $ char.
Unfortunately, I don't think there is a way to bypass this behavior, however you can make your own filter and use it in ng-repeat.
This is simple example that should work for you:
JS
app.filter('customFilter', function() {
return function(items, keyword) {
if (!keyword || keyword.length === 0) return items;
return items.filter(function(item){
var phrase = keyword.$.toLowerCase();
return item.gd$name.gd$fullName.$t.toLowerCase().includes(phrase) ||
item.gd$name.gd$familyName.$t.toLowerCase().includes(phrase) ||
item.gd$name.gd$givenName.$t.toLowerCase().includes(phrase) ||
item.gd$email[0].address.toLowerCase().includes(phrase) ||
item.gd$phoneNumber[0].$t.toLowerCase().includes(phrase) ||
(!!item.gd$organization[0].gd$orgTitle && item.gd$organization[0].gd$orgTitle.$t.toLowerCase().includes(phrase)) ||
(!!item.gd$organization[0].gd$orgName && item.gd$organization[0].gd$orgName.$t.toLowerCase().includes(phrase));
});
}
});
HTML
<tr ng-repeat="x in obj | customFilter:searchText">
Of course, you will have to add more checks for possible null values. I've just wanted to make it work on the data you've provided.
Hope, you'll find it useful.
Here's plunk
I can't comment because my reputation is less than 50 but as far as i can tell it's any property that has a $ in it's name is not used in the filter.. I tried changing the property names and this fixed the issue. Realise you may or may not have control over this.
Suppose your obj is as below:
$scope.obj=[{firstName:'Jeet',lastName:'kumar'},{firstName:'test1',lastName:'dev'},{firstName:'test2',lastName:'other'}];
Search input box
<input type="text" name="search" ng-model="searchText" />
Datatable filter by index 'firstName'
<tr ng-repeat="x in obj | filter:{firstName:searchText}">
<td>{{x.firstName}}</td>
<td>{{x.lastName}}</td>
</tr>
Datatable filter over all index
<tr ng-repeat="x in obj | filter:searchText">
<td>{{x.firstName}}</td>
<td>{{x.lastName}}</td>
</tr>
Desc:
filter:{name:searchText}
filter on the basis of 'firstName' index from your $socpe.obj array

Model value is not reflected completely in UI - Angular js

I have a method to save an object. That object is added to an array after its saved. The object has many properties . So, before adding the object to an array I am modifying few properties. Few of them don't reflect in UI .
Code :
HomeController.js
$scope.MainArray=[];
$scope.newItem={};
AdjustmentController.js
$scope.Save = function(item){
$scope.newItem={};
var promiseObj= $http.post('My_Url',{expectedItem: item});
promiseObj.success(function(data,status){
$scope.newItem.Id= data;
$scope.newItem.dataList= item.dataList;
$scope.newItem.LatestComment = item.LatestComment;
$scope.newItem.CreatedDate = item.CreatedDate;
if($scope.MainArray.length==0){
$scope.MainArray.push($scope.newItem);
}
else{
$scope.MainArray.unshift($scope.newItem);
}
})
}
HTML :
<body ng-controller="HomeController">
<div ng-controller="AdjustmentController">
<div ng-repeat="item in MainArray ">
<!-- This past is not updated -->
<span>{{item.LatestComment}}</span>
<span>{{item.CreatedDate}}</span>
<!-- This past is updated -->
<span>{{item.DataList[0].text}}</span>
<span>{{item.DataList[1].text}}</span>
<span>{{item.DataList[2].text}}</span>
<span>{{item.DataList[3].text}}</span>
</div>
</div>
</body>
The value is changes if I console and see. But in UI it updated only few values and LatestComment and CreatedDate is not updated.
I have also tried using $scope.$apply() , but it did not work.
You need to initialize variable $scope.MainArray when controller loads, then after you need to just over write it when it will needed to save.
In your controller define variable like this :
$scope.MainArray=[];
and then use it in your save object function.
Here, you only send the item to your backend:
var promiseObj= $http.post('My_Url',{expectedItem: item});
and here you expecting it to be changed:
$scope.newItem.dataList= item.dataList
$scope.newItem.LatestComment = item.LatestComment;
$scope.newItem.CreatedDate = item.CreatedDate;
Your answer is contained in the data object, not the item. item won't ever change this way.

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>

Resources