I have data:
data = {
"laptop": [
"dell",
"hp",
"lenovo",
"acer",
"asus"
],
"mobile": [
"lenovo",
"motorolla",
"apple",
"samsung"
]
}
I am trying to display it in the table using the ngFor for displaying the data in the below format
But I am unable to get the data in the below rather than I am getting only data in the traditional format leaving laptop,mobile keys
is there any way to do that in the template
Stackblitz demo
is there any alternative approach or better becoz in future i may get n rows for the table
If you are using angular 6.1 you can use keyvalue
<div *ngFor="let title of data | keyvalue">
{{title.key}}
</div>
Example :https://stackblitz.com/edit/keyvalue-pipe
You can use this :
get dataKeys() { return Object.keys(this.data); }
This will create an array of the keys of your object.
You can now use a loop on it :
<div *ngFor="let key of dataKeys">
<div *ngFor="let item of data[key]">...</div>
</div>
Related
Currently working with Bootstrap-vue. I need to generate b-table but with dynamic header values which I get from api, not sure how to go about doing this.
I have tried regular way to set fields in data which works fine but if I try to set computed fields I get no values in my table .
`
computed: {
fields () {
return ['date', ...this.scheduler.times]
}
}
`
The this.scheduler.times is data received from api which contains array like below. Also this array can have more times added
(data from api)
`
[
{
"id": 1,
"start": "01:30:00",
"end": "09:30:00"
},
{
"id": 2,
"start": "10:00:00",
"end": "13:00:00"
}
]
`
Expected result would be where I have columns headers with times from api and added column of dates.
I can generate series of dates using moment but not sure how will i map this to the b-table
Below is a screenshot of result I would like to get:
Any help would be greatly appreciated.
Thanks
I think this is something, you are looking for:
<b-table :items="items" :fields="fields">
<template v-for="field in dynamicFields" v-slot:[`cell(${field.key})`]="{ item }">
</b-table>
in scripts:
this.dynamicFields.push({key: 'someTestKey', label: '1:30AM - 2:30AM'})
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.
My data called from a JSON is very simple.
I want to filter all data where the id of events is 13
My json provides from [...] $scope.things = things
[
{
"id":"1",
"title":"title1",
"events":[
{"id":"11",
"events11"},
{"id":"12",
"events12"}
]
},{
"id":"2",
"title":"title2",
"events":[
{"id":"11",
"events11"},
{"id":"13",
"events13"}
]
}
]
I try to display with :
<ion-item collection-repeat="thing in things | filter:{events.id:'13'}">
{{thing.id}}
</ion-item>
Very 1st thing you need to correct you JSON format, like events11, events12 & events13 should be key value pair like such "events": "11", "events": "12" & "events": "13".
Then you could use deep filter like below.
Markup
<ion-item collection-repeat="thing in things | filter:{events: {id:'13'}}">
{{thing.id}}
</ion-item>
Plunkr here
You could filter directly in the controller when instantiating the scope variable:
$scope.things = things.filter(obj => obj.id==='13');
You could try it with ng-if and a helper function:
<ion-item collection-repeat="thing in things" ng-if="getEventInThing(thing, '13')">
{{thing.id}}
</ion-item>
The following function will return the event with the given id, if present:
$scope.getEventInThing = function(thing, eventId) {
return thing.events.find(function(event) {
return event.id===eventId;
});
}
<ion-item collection-repeat="thing in things">
<span ng-repeat="event in thing.events" ng-if="event.id='13'"
{{thing.id}}
</ion-item>
Basically two loops with an ng-if for the inner loop to check if the even's id is 13.
This should be a very simple thing to do. I am building an IONIC app with a JSON data file. The data is something like this.
[
{ "id": 1,
"name": "John",
"type": "male",
"bio": "this is John"
},
{ "id": 10,
"name": "Mary",
"type": "female",
"bio": "this is Mary"
}
]
Now I want to filter by by "type" in the data and then loop the data by "id".
<ion-list ng-repeat="person in people | filter: {'type': 'male'}">
<ion-item href="#tab/people/males/{{ person.id }}">{{ person.name }}
</ion-item>
</ion-list>
The Controller for this is:
.controller('PeopleController', ['$scope', '$state', '$http', function($scope, $state, $http){
$http.get('data/people.json').success(function(data){
$scope.people = data;
$scope.whichPerson = $state.params.id;
}),
}])
This displays the required data of males only by name.
However if I want to see the individual bio using the following code
<div class="card" ng-repeat="person in people | filter: { id: whichPerson }">
<h2>{{ person.name }}</h2>
<p>{{ person.bio}}</p>
</div>
When I click the individual item for each person to display person.bio I get both John and Mary.'
I figured this was because the "id" is 1 and 10 which seems to be parsing as a string to the controller. I tried putting this
"id": "1" and "id": "10"
Did not work. I did this in the controller
$scope.whichPerson = parseInt($state.params.id, 10);
This does not work either. I am totally stumped. How do I get the individual id's from the data? In fact I noticed that I can change the id to 11 or 12 or 13 etc and it still returns both records?
Any help appreciated.
Try to add the comparator :true to your filter as described in the documentation. This forces a strict comparison of the filter value instead of just checking if the data contains it.
Given the above doesn't work, you could try a custom filter by doing:
filter: { id: whichPerson }:sameID
and then in your controller:
$scope.sameID = function(actual, expected) {
return parseInt(actual) === parseInt(expected)
};
Even if this doesn't work, you could then at least debug within the custom filter to see where the comparison is failing
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.