HTML code:
<li ng-repeat="obj in objects">{{obj.name}} <a ng-click="remove($index)">x</a></li>
JavaScript code:
$scope.remove = function(index){
$scope.objects.splice(index, 1);
}
JSON data:
{
"0": { "name": "name1" },
"1": { "name": "name2" }
}
When remove() is called, I get TypeError: $scope.objects.splice is not a function, here I know $scope.objects is not an array and so splice() will not work.
Is there any method to remove the selected index??
Thanks in advance...
Since you're using a json object and not an array you can use ng-repeat like this
<li ng-repeat="(key,value) in objects">{{value.name}} <a ng-click="remove(key)">x</a></li>
So that the remove method can delete current list element by key:
$scope.remove = function(key) {
delete $scope.objects[key];
}
Here's a plunker.
$index is quite confusing in cases like this as it is dynamic whereas the keys are not.
Related
I need to sort my json data object before render the browser. this is the my json format
$scope.cityData= [
{
id: '520',
city:'col01'
},
{
id: '410',
city:'col02'
},
{
id: '412',
city:'col03'
}]
I tried to do it. but something wrong in my code. I console log it. but did not sort
$scope.cityData.sort(function (a, b) { return a.id - b.id });
console.log($scope.cityData);
$scope.newCitySort = $scope.cityData;
I need to assign this sorted data to new scope variable also. how i do this ?
If you don't need the actual $scope.cityData to be sorted. You can just use the orderBy filter
In your html
<ul ng-repeat="city in cityData | orderBy: 'id' ">
<li>**your list rendering code here**</li>
</ul>
And this will render your collections ordering it by id
I have a list of data displayed on my page that is broken down into divs. Each div represents an array of data in my object, pretty common.
I am trying to add a text box to my page where I can filter out the data and it will narrow down the results shown on the page as more data is entered into the text box.
For that, I added a filter on my ngFor like so: *ngFor="let x of data | filter: filterString".
My text-box then uses ngModel to filter that data down:
<input type="text" class="form-control" placeholder="Filter..." name="ruleFilter" id="ruleFilter" [(ngModel)]="filterString" (keyup)="onFilter($event)">
The issue I am having is that the filter seems to only be working with the top layer of data in my object. For example, the data below is what one of the results looks like in my ngFor loop. I can search Omaha just fine since its in the top level and it filters it down correctly.
However, If I look for something like Campus which is nested inside Attribute, it doesn't find it in the filter and no results are shown.
{
"RuleParentID": "618",
"RuleVersionID": "18",
"MappedValue": "1",
"ProcessingOrder": 1,
"KeyID": "1",
"Value": "Omaha",
"IsRuleRetired": "0",
"UserImpactCount": "0",
"Attribute": [
{
"AttributeID": "6",
"AttributeName": "Campus",
"Operator": {
"OperatorID": "3",
"OperatorName": "In List",
"SqlOperator": "IN"
},
"AttributeValue": [
{
"AttrValue": "1",
"Value": "Omaha",
"IsValueRetired": "0",
"disabled": "False"
}
]
},
{
"AttributeID": "14",
"AttributeName": "Grade",
"Operator": {
"OperatorID": "1",
"OperatorName": "Greater Than",
"SqlOperator": ">"
},
"AttributeValue": [
{
"AttrValue": "14",
"Value": "14",
"IsValueRetired": "0",
"disabled": "False"
}
]
}
]
}
Is there any way to have the model look at all layers of the object for my binding instead of just the top layer (which I only assume its doing at this time) ?
Update: Here is a plunker of what my basic setup is like: https://plnkr.co/edit/eywuWmPRseUkmVPbTEOf?p=preview
You will see the data model that searches by the top level properties just fine, but when I search for something nested, I don't get any results back.
If I understand well the question, I think that to flat the data will help you:
var flattenObject = function(ob) {
var toReturn = {};
for (var i in ob) {
if (!ob.hasOwnProperty(i)) continue;
if ((typeof ob[i]) == 'object') {
var flatObject = flattenObject(ob[i]);
for (var x in flatObject) {
if (!flatObject.hasOwnProperty(x)) continue;
toReturn[i + '.' + x] = flatObject[x];
}
} else {
toReturn[i] = ob[i];
}
}
return toReturn;
};
let newData = flattenObject(data);
Code source: https://gist.github.com/penguinboy/762197
To achieve expected result , use below option
1.In your component below variable
jsonVal:any=JSON; // for using JSON.stringify and indexOf
Use *ngIf to filter value from input with indexOf
<input type="text" [(ngModel)]="filterString">
<div *ngFor="let data of result">
<div *ngIf="jsonVal.stringify(data).indexOf(filterString)!= -1">{{data| json}}</div>
</div>
code sample for reference - https://stackblitz.com/edit/angular-ht2afv?file=app/app.component.html
Just for testing , I have added another Object with Campus2 and Omaha2
When filtering on a nested property of data you can use the map function or similar.
This will be in your component and not the template. Filtering using pipes in the template is discouraged by the Angular team for performance reasons.
Instead I would do something like this:
const data = [{//your data}]
let filteredData = [];
data.map(val => {
if (val.Attribute.filter(name => name.AttributeName === "Foo").length > 0) {
filteredData.push(val)
}
});
I am assuming your data is an array of objects.
Beware I am mutating my data object. To avoid this you do this:
const data = [{//your original data}]
const dataToFilter = JSON.Parse(JSON.stringify(data))
This will make copy of your data without references to your original object. Useful if you want to clear your filter. Not useful if your data object contains functions.
On re-reading your question I think this is not the solution you were looking for but rather a method to look anywhere in the data. For this you should probably flatten your data as suggested by Zelda7. Another approach would be to extend a filtering method to explicitly filter on all relevant fields.
I have an element in my View in Aurelia that is not getting updated when an object from its Viewmodel is getting updated. I've seen the documentation about Pub/Sub and Event Aggregators, however this seems a little heavy-handed for what I want to do, since I am not trying to communicate between two different resources, but rather just within a View and its Viewmodel.
When a change occurs to the object in the Viewmodel, I don't know how to correctly update (or trigger an update to) the string interpolation in the View.
My code is as follows
myview.html
<h1>My List</h1>
<ul>
<li repeat.for="group of modelObject.groups">
<span>${group.id}</span>
<span repeat.for="state of group.region">${state}</span>
</li>
<ul>
<button click.delegate(editModelObject())>Edit</button>
myviewmodel.js
constructor()
{
this.modelObject = {
<other stuff>,
"groups": [
{
"id": "default",
"regions" : ["NY", "CT", "NJ"]
},
{
"id": "west",
"regions" : ["CA", "OR"]
}
],
<more stuff>
}
}
editModelObject() {
<something that updates both the id and regions of a group in this.modelObject>
}
For some reason, the states are correctly changing in the view, but the id's are not. Do I need to use something like Pub/Sub to get the two-way binding to work correctly? Or is there a simple thing that I am missing or doing wrong?
This works if you change a property of one of the array's objects. But this doesn't work if you assign one of the array's index because this would require dirty-checking. See https://github.com/aurelia/binding/issues/64
To solve your problem you should use splice() instead of indexed assignment. For instance:
const newItem = { id: 77, name: 'Test 77', obj: { name: 'Sub Name 77' } };
//instead of this.model.items[0] = newItem; use below
this.model.items.splice(0, 1, newItem);
Running example https://gist.run/?id=087bc928de6532784eaf834eb918cffa
I am trying to use a ng-repeat filter, however i can't seem to get it working.
html:
<li dnd-draggable="item" ng-repeat="item in items| filter: integrateFilter">
</li>
Filter:
$scope.integrateFilter = function (item) {
return !$scope.integratesInput ?
item : (item.type == $scope.itemTypes[0].type);
};
The structure of the data:
$scope.itemTypes is an array of types that i want to filter with:
products: Array[2]
0: Object
type: "food"
1: Object
type: "beverage"
The "items" in the list is an array of objects like:
0: Object
name: "steak"
type: "food"
So basically i want to filter items with an Array ($scope.itemTypes). The filter i'm using right now only returns one result (0) the beginning of the array. is there a way to use a filter like this? or will i need to loop through the $scope.itemTypes?
Thanks
Here is my simple code:
in app.js:
$http.get($rootScope.config.app_ws+'jsons/json.json').success(function(response) {
$rootScope.config.app_genres = response;
});
the json.json:
{
"genres":{
"Ambient":{},
"Alternative":{},
"Blues":{},
"Chillout":{},
"Classical":{},
"Country":{},
"Dance":{},
"Dubstep":{},
"Electronic":{},
"Folk":{},
"Grunge":{},
"Hip Hop":{},
"House":{},
"Indie":{},
"Jazz":{},
"Latin":{},
"Metal":{},
"Opera":{},
"Pop":{},
"Punk":{},
"R&B":{},
"Reggae":{},
"Rock":{},
"Ska":{},
"Soul":{},
"Vocal":{},
"Funk":{},
"Lounge":{},
"Geek":{}
}
}
the HTML:
<div ng-repeat="i in config.app_genres.genres">
<span class="span3x3" ng-if="$first">Others</span>
<span class="span3x3">{{i}}</span>
<div class="row-fluid" ng-if="($index%3) == 1"></div>
i'm just trying listing in html all the json genres names , so for example Alternative, Ambient, Pop, Rock, etc but actually it prints {} instead of the genre Name.
What's happening?
Genres is an object, not a array. This means it doen't have a list of elements, but a list of (key, value) pairs. In your case, the keys are the names of the genres and the values are empty objects.
What happens is that ng-repeat iterates by default on the values. So you have several options:
If you only need the genre names, try a JSON array instead:
{
"Genres": [
"Pop",
"Rock",
...
"Jazz"
]
}
If you need further details, iterate on both keys and values:
<div ng-repeat="(genre, details) in config.app_genres.genres">
With a JSON like:
{
"Genres": {
"Jazz": {
"songs": 50
},
"Pop": {
...
}
}
}
Now that I look at the JSON file it actually prints the right value.
If you see, you are using an "object literal" while you should have an array instead
"Genres": ["Ambient", "Alternative", .., "Jazz"]
At the very moment, the value of every genre is actually { } which is the value that is printed in your HTML.