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

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>

Related

How to loop through json defined in typescript

I'm working with Angular. There is a similar question but not answered -
How to loop through a JSON object with typescript
I'm not getting any error or warning. But I'm not getting the output also. I'm trying to imitate twitter-api. I've created a json object in my typescript and I'm trying to loop through my json in HTML. Here's my code:
twitter-timeline.component.ts
output: JSON;
twitter_data:any = {
statuses: [
{screen_name:"tanzeel", status: "wonderful day, enjoying at beach"},
{screen_name:"pablo", status: "what a lovely morning #surfing #beach #relax"},
{screen_name:"ricky", status: "feeling sick :-( #typhoid"}
]
}
ngOnInit() {
this.output = <JSON>this.twitter_data;
}
twitter-timeline.component.html
<div class="container" *ngFor="let tweets of output; let i=index">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12 text-column">
<p class="screen-name">{{tweets.statuses[i].screen_name}}</p>
<p class="user-status">{{tweets.statuses[i].status}}</p>
<br>
</div>
</div>
</div>
Is there anything wrong with the way I'm creating JSON object, or there's something wrong with the way I'm reading values in HTML. Please correct me.
I also tried this kind of JSON structure:
output: JSON;
obj: any =
{
"col1":{"Attribute1": "value1", "Attribute2": "value2", "Attribute3": "value3"},
"col2":{"Attribute1": "value4", "Attribute2": "value5", "Attribute3": "value6"},
"col3":{"Attribute1": "value7", "Attribute2": "value8", "Attribute3": "value9"}
};
You need to change *ngFor as *ngFor="let tweets of output.statuses; let i=index" .
output is an object so, you cannot iterate object like this, instead iterate the array output.statuses and then you can get the related data like,
<p class="screen-name">{{tweets.screen_name}}</p>
<p class="user-status">{{tweets.status}}</p>
You need to change let tweets of output to let tweets of output.statuses.
twitter-timeline.component.html
<div class="container" *ngFor="let tweets of output.statuses; let i=index">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12 text-column">
<p class="screen-name">{{tweets.screen_name}}</p>
<p class="user-status">{{tweets.status}}</p>
<br>
</div>
</div>
</div>
Working Stackblitz

How to display an object's variable's name in HTML?

I seem to be repeating myself when building a detail class to display object data. Is there a way to *ngFor: for each attribute of the rug object, display the attribute's name, and then bind it to the object's value?
//rug-detail.component.ts
<div class="row">
<div class="col-md-3">Name:</div>
<div class="col-md-6">{{rug.name}}</div>
</div>
<div class="row">
<div class="col-md-3">ID:</div>
<div class="col-md-6">{{rug.id}}</div>
</div>
<div class="row">
<div class="col-md-3">Availability:</div>
<div class="col-md-6">{{rug.availability}}</div>
</div>
<div class="row">
<div class="col-md-3">Price:</div>
<div class="col-md-6">{{rug.price|currency:"USD":"symbol"}}</div>
//rug.ts
export interface Rug{
name: string;
id: number;
availability: String;
price: number;
}
The same question, for Ruby: Accessing a variable's name from an object
A hint:
rug = {
name: "Name",
id: 42,
availability: "in stock",
price: 123,
};
for (const key in rug) {
console.log(`${key}: ${rug[key]}`)
}
// OR
for (const key of Object.keys(rug)) {
console.log(`${key}: ${rug[key]}`)
}
One of the two must be usable in Angular's *ngFor

How to pass info to directive when looping through Angular array?

I am using an array of objects to populate info in a directive, but I do not know, when looping through that array, how to insert each object in the array into the "info" parameter of my directive.
Basically, the HTML template uses data passed to it in the info parameter, like so:
<directive info="{{angular object}}"></directive>
I know how to do this when I've hard-coded individual objects in the controller, like so:
$scope.object1 = {...values here...}
$scope.object2 = {...values here...}
etc.
For this I use:
<directive info="object1"></directive>
<directive info="object2"></directive>
But when I'm looping, I can't do that because I need to repeat the directive for each object in the array.
Here's what i've got
<div class="main" ng-controller="MainController">
<div class="container">
<div class="card" ng-repeat="app in apps">
<app-info info="{{app}}"></app-info> <!--HERE IS MY PROBLEM-->
</div>
</div>
</div>
Obviously I have no idea how or what to put as a value for the "info" parameter.
My MainController is as follows:
$scope.apps = [
{
icon: 'img/move.jpg',
title: 'MOVE',
developer: 'MOVE, Inc.',
price: 0.99
},
{
icon: 'img/gameboard.jpg',
title: 'Gameboard',
developer: 'Armando P.',
price: 1.99
},
{
icon: 'img/forecast.jpg',
title: 'Forecast',
developer: 'Forecast',
price: 1.99
},
{
icon: 'img/shutterbugg.jpg',
title: 'Shutterbugg',
developer: 'Chico Dusty',
price: 2.99
}];
The result is empty, meaning when I load the webpage, there is nothing there.
Just remove brackets. You were close.
<div class="main" ng-controller="MainController">
<div class="container">
<div class="card" ng-repeat="app in apps">
<app-info info="app"></app-info> <!--HERE IS NO PROBLEM-->
</div>
</div>
</div>

Angular + Typescript: Add to array, ng-repeat adds blank row

Trying to add a new object to an array and have it show up in an ng-repeat div. I add the object, look at the array in Chrome's dev tools and can see the new object in there, but the ng-repeat section just has a blank row. I've search throughout StackOverflow, implemented many solutions and still have this problem.
HTML:
<div ng-repeat="subItem in ec.mainItem.SubItems">
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="col-md-3 h4">
<button class="btn-link">{{subItem.Name}}</button>
</div>
<div class="col-md-6">
{{subItem.Description}}
</div>
</div>
</div>
</div>
</div>
ItemCtrl.ts
module MainItemApp {
'use strict'
export class MainItemEntryCtrl implements IMainItemCtrl {
static $inject = ['$scope', '$routeParams', 'ItemSvc'];
public mainItem: MainItem; //this has an array on it named SubItems
public sub_item_name: string;
public sub_item_description: string;
public sub_item_date: Date;
public sub_item_start_date: Date;
public sub_item_end_date: Date;
public sub_item_descriptive_location: string;
public sub_item_short_location: string;
constructor($scope, $routeParams: IItemEntryRouteParams, itemSvc: ItemSvc) {
this.id= this.getId($routeParams.id);
if (this.id!= undefined) {
itemSvc.getMainItem(this.id).then(
(data) => this.mainItem = data);
}
}
addSubItem() {
var subItem = {
id: '',
name: this.sub_item_name,
itemDate: this.sub_item_date,
startDate: this.sub_item_start_date,
endDate: this.sub_item_end_date,
description: this.sub_item_description,
descriptiveLocation: this.sub_item_descriptive_location,
shortLocation: this.sub_item_short_location,
geoLat: '',
geoLong: '',
groupItems: []
};
this.mainItem.SubItems.push(subItem);
}
}
When I click a button, AddSubItem runs, the item gets created and after the push, I can hover over subItems and see the array has two objects, the one I loaded with and the one I pushed, but the HTML that's generated gives me this:
<div ng-repeat="subItem in ec.mainItem.SubItems">
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="col-md-3 h4">
<button class="btn-link">Some Item</button>
</div>
<div class="col-md-6">
Some Description
</div>
</div>
</div>
</div>
</div>
<div ng-repeat="subItem in ec.mainItem.SubItems">
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="col-md-3 h4">
<button class="btn-link"></button>
</div>
<div class="col-md-6">
</div>
</div>
</div>
</div>
</div>
Any ideas? Any help would be greatly appreciated!
Sorry, bad post, I figured it out (isn't it always like that, as soon as you make a fool of yourself and ask, you figure it out). My data was coming back from the API with capitalized property names (i.e. Name, Description) and I was adding an object where the names were lowercase (i.e. name, description) so of course there was nothing to show in the newly added row. So I synced up the names coming from my API with the names in the Typescript classes and everything is working now. So of course when I searched for the answer, I couldn't find it: no one posted "Hey dummy! Check the casing on your properties!"
So I think I will leave this up just in case someone else runs across the same problem and it sparks them to check their casing.

How to recombine key and value into an object?

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 **/
}