How to recombine key and value into an object? - json

In my Angular app, I am using ng-repeat to cycle through all the items in a JSON object I have. So for example, for my JSON object:
$scope.animals =
{
horse: {
sound: "Nay",
legs: 4,
}
beaver: {
sound: "thwack",
legs: 2
}
}
I want to cycle through to get a list consisting of Horse, Beaveri.e.
<div ng-repeat="(key, value) in animals">
<div class="niceBox">
<h1> {{key}} </h1>
</div>
</div>
but for each animal, I want to have a button that takes the whole object and adds it to a list of my favorite animals. Something like this:
<div ng-repeat="(key, value) in animals">
<div class="niceBox">
<h1> {{key}} </h1>
<div ng-click="addToFavorites(animal)">Add To Favorites</div>
</div>
</div>
The Trouble Is that I can't just pass animal as a parameter since I broke up the ng-repeat into (key, value) already.
How do I reassemble (key, value) so I could use the object as a whole?

Your question is misleading, because there's no original "object" you want to re-assemble - there's just property names and values. If you had a single object for the animal in the first place:
var animals = [{
name: 'horse',
sound: ...,
...
}, {
name: 'beaver',
...
}, ...];
there would be nothing to "re-assemble", you'd just use it:
<div ng-repeat="animal in animals">
{{animal.name}}
<button ng-click="addToFavorites(animal)">...</button>
</div>

Try by this this
<div ng-repeat="(key, value) in animals">
<div class="niceBox">
<h1> {{key}} </h1>
<div ng-click="addToFavorites(key, value)">Add To Favorites</div>
</div>
</div>
And in your controller
$scope.addToFavorites = function(key, value) {
$scope.animal = {};
animal[key] = value;
/** your code **/
}

Related

how to display data with *ngFor

i trying to display data with *ngFor, but for some reason this doesn't display any data, and any error.
I already tried alot of samples that i found in internet, none of those worked so i decide to ask here.
here is what i have:
ts file:
public querySuccess: any[];
this.userService.getMentions().subscribe(
(returnAPI) => {
this.querySuccess = returnAPI.data;
});
my html:
<div *ngIf="returnAPI">
<div *ngFor="let key of querySuccess">
<div>{{querySuccess.firstName}}</div>
</div>
</div>
<div *ngIf="!returnAPI">
<div>0 results found!</div>
</div>
the getMentions().subscribe() return this Json:
{
total: 3,
data:[
{userId: 0, firstName: "test", lastName: "xzy"},
{userId: 0, firstName: "john", lastName: "yeet"},
{userId: 0, firstName: "jamal", lastName: "abc"}]
}
You don't need that if condition to loop that ngFor.If its to show that no data error message use querySuccess because returnAPI does not seems to defined anywhere.
<div *ngIf="querySuccess">
<div *ngFor="let key of querySuccess">
<div>{{key.firstName}}</div>//key is single istance queryselector is full array.
</div>
</div>
<div *ngIf="!querySuccess">
<div>0 results found!</div>
</div>
you can try like this
<div *ngIf="returnAPI">
<div *ngFor="let key of querySuccess">
<div>{{key.firstName}}</div> <!-- key instead of querySuccess -->
</div>
</div>
Hi i would firstly recommend you put your code in a function like
ngOnInit() {
this.getAllQueries();
}
getAllQueries() {
this.userService.getMentions().subscribe(
(returnAPI) => {
this.querySuccess = returnAPI.data;
return this.querySuccess;
});
}
make sure you call this in the ngOninit function or your constructor

Template view changes iterating through JSON object when index goes beyond 10

I have JSON object like this.
{
CR1: "aaa"
CR2: "bbb*2"
CR3: "ccc/2"
CR4: "ddd-23"
CR5: ""
CR6: "SS"
CR7: ""
}
The index after 'CR' is added dynamically and in template when iterated using ngFor it takes view as below:
But when CR index goes above 10 the view changes something like this:
Here is code from template:
<div class="row mt-10" *ngFor="let item of computationLogicObj | keyvalue; trackBy: trackByFn">
<div class="col-md-4">
<label class="form-control-label" for="field_{{item.key}}">{{item.key}}</label>
</div>
<div class="col-md-6">
<input type="text" class="form-control" id="{{item.key}}" name="{{item.key}}" [(ngModel)]="computationLogicObj[item.key]" [disabled]="!isInternal">
</div>
<div class="col-md-2">
<a (click)="deleteComputationLogic(item.key)">
<fa-icon [icon]="'times'"></fa-icon>
</a>
</div>
</div>
and trackByFn
trackByFn(index: any, item: any) {
return item.key;
}
In console the json object is shown like below, which is expected:
{
CR1: "aaa"
CR2: "bbb*2"
CR3: "ccc/2"
CR4: "ddd-23"
CR5: ""
CR6: ""
CR7: ""
CR8: ""
CR9: ""
CR10: ""
CR11: ""
}
What exactly is changing this view then?
keyvalue pipe sorts the keys you provide. as a result 'CR10' < 'CR2' and it appears upper in the list. I suggest keeping your data structure as array of {key: string, value: string} objects and eliminate usage of keyvalue pipe

How to bind JSON object key value pair separately to angular template

And i have a dynamic json coming from an API as below:
{123: "Mumbai", 456: "Bangalore", 789: "Chennai", 101: "Andhra",...}
I have below HTML code written in my template in which I am getting image-1, image-2 logos from my assets folder
<div class="row">
<div class="col-6" (click)="cityClick('Bangalore')">
<div class="img-1">
// my image-1 logo goes here
</div>
<div class="img-text">
Bangalore
</div>
</div>
<div class="col-6" col-6 (click)="cityClick('Mumbai')">
<div id="image_block" class="img-2">
// my image-2 logo goes here
</div>
<div id="text_block" class="img-text">
Mumbai
</div>
</div>
</div>
How to get the key of the json when i click on image and also display the text below the image from the corresponding key-value.
And when i click i should be able to pass the key and text inside the click event. Please help as i am new to Angular!
First convert this JSON into an JavaScript/TypeScript array like below:
var json = {123: "Mumbai", 456: "Bangalore", 789: "Chennai", 101: "Andhra" };
var jsonToBeUsed = [];
for (var type in json) {
item = {};
item.key = type;
item.value = json[type];
jsonToBeUsed.push(item);
}
This will result in data like below:
Now use NgFor in the template to bind array. (Refer this for NgFor)
<div class="row">
<div *ngFor="let item of array">
<div class="col-6" (click)="cityClick(item)">
<div class="img-1">
// my image-1 logo goes here
</div>
<div class="img-text">
{{item.value}}
</div>
</div>
</div>
</div>
We have passed the whole object in the click event. You can read any of the desired property from the object in click event handler which you will write in the component.
For your special requirement, you can use below markup:
<div class='row' *ngFor='let index of array; let i = index; let even = even'>
<div *ngIf="even" class='col-6' (click)="cityClick(array[i])">
<div class="img-1">
// my image-1 logo goes here
</div>
<div class="img-text">
{{array[i].value}}
</div>
</div>
<div *ngIf="!even" class='col-6' (click)="cityClick(array[i])">
<div class="img-1">
// my image-1 logo goes here
</div>
<div class="img-text">
{{array[i].value}}
</div>
</div>
</div>
Use this below function in your code:
getKeyByValue(object, value) {
return Object.keys(object).find(key => object[key] === value);
}
And use as
var dynamicJson = {123: "Mumbai", 456: "Bangalore", 789: "Chennai", 101: "Andhra"}
cityClick(value){
var key = this.getKeyByValue(this.dynamicJson, value);
console.log(key);
}
{123: "Mumbai", 456: "Bangalore", 789: "Chennai", 101: "Andhra",...}
Do you have influence on that JSON? This highly looks like a design issue for me. I assume those numbers are id's. I believe somethings like this should be better:
[{id: "123", name: "Mumbai"}, {id: "456", name: "Bangalore"}, {id: "789", name: "Chennai"}, {id: "101", name: "Andhra"},...}]
In that case you receive an array of cities, which could be an interface to parse to.
export interface City {
id: string;
name: string;
}
And you can easily render it in html by using *ngFor
<div *ngFor="let city of cities">
<!--do something with city.id and city.name-->
</div>
<div *ngFor let value of json |keyvalue > </div>

Meteor #each block issues

I would like to iterate over a Mongo query for the user's collections using the each block.
I have the following html template that should load in different pieces of data from the profile object in the users collection.
To clarify, the users Collection has a services, status and profile object
{{#each profile}}
<div class="profileUser oneDiv">
<div class="profileUserLeft">
<div class="profileUserImage">
<div class="spin"> {{> spinner}} </div>
<img src="{{profile.picturelrg}}" class="profileUserImg">
</div>
<div class="profileUserGraph">
<label for="myChart"><b>Meetup Graph</b>
<br>
<span class="profileMonth"> {{profile.month}} </span>
<br>
<canvas id="myChart"></canvas>
</label>
</div>
</div>
<div class="profileUserRight">
<div class="profileUserName">
<ul>
<li><h1>{{profile.name}}</h1></li>
<li>
<div class="circle" style="background-color: {{online.color}}"></div>
</li>
</ul>
</div>
</div>
</div>
{{/each}}
Here is my helper that sets the query
profile: function() {
return Meteor.users.find({
_id: id
});
}
Currently the page loads in no data.
When I statically query for a property however it works. This is done like so.
profimg: function() {
return Meteor.users.find({
_id: id
}).fetch()[0].profile.picturelrg;
}
How can I be more efficient and use the each block instead of statically searching for each different property utilizing the fetch() method?
each of Blaze takes an array as parameter to loop while find method return a Cursor of MongoDB. What you need to do is fetch the Cursor to return the array
profile: function() {
return Meteor.users.find({
_id: id
}).fetch();
}
However, your logic is not correct. You are finding the profile that matches with the input id, thus the function should be
profile: function() {
return Meteor.users.findOne({
_id: id
});
}
and then you can access the property without the each loop

AngularJS: How to get the key of a JSON Object

I am unsure if this has got anything to do with AngularJS at all and if it is only JSON related.
Anyhow, let us say that we have the following JSON:
$scope.dataSets = {
"names": ["Horace", "Slughorn", "Severus", "Snape"],
"genders": ["Male", "Female"]
}
Now, I am using the ng-repeat directive to print the above as follows:
<div ng-repeat="data in dataSets>
//Continue readig to know what I am expcting here
</div>
What I expect within the <div></div> tags is to print "name" and "genders". That is, I wish to print the keys of the JSON. I have no idea what the keys are, as in they could be anything. How can I do this?
As docs state it:
(key, value) in expression – where key and value can be any user defined identifiers, and expression is the scope expression giving the collection to enumerate.
<div ng-repeat="(key, data) in dataSets">
{{key}}
</div>
for accessing Json key-value pair from inside controller in AngularJs.
for(var keyName in $scope.dataSets){
var key=keyName ;
var value= $scope.dataSets[keyName ];
alert(key)
alert(JSON.stringify(value));
}
if dataSets is an array and not an object you first need to ng-repeat the array items and then the key or value.
<div ng-repeat="item in dataSets">
<div ng-repeat="(key, value) in item">
{{key}}
{{value}}
</div>
</div>
just my 2 cents.
For every dataSet in dataSets, print the key and then iterate through the individual items:
<div ng-repeat="(key, dataSet) in dataSets">
<div>{{key}}</div>
<div ng-repeat="value in dataSet">
{{value}}
</div>
</div>
{{dataset}} can be displayed in one go also, the array would be displayed as a comma separated list of values.