Reading JSON Response in AngularJS - javascript

I have an angular controller called productImages which returns following JSON data:
{
"Product_1":[
{ "image_id":"12469",
"name":"My Product 1 - Variety 1",
"url":"\/\/mystorefront.net\/120\/small\/1911791794.jpg"
},
{
"image_id":"12470",
"name":"My Product 1 - Variety 2",
"url":"\/\/drfuittf5cya9.cloudfront.net\/121\/small\/1911802897.jpg"
}
],
"Product_2":[
{ "image_id":"122349",
"name":"My Product 2 - Variety 1",
"url":"\/\/drfuittf5cya9.cloudfront.net\/122\/small\/1911791794.jpg"
},
{
"image_id":"123470",
"name":"191123897.jpg",
"name":"My Product 2 - Variety 2",
"url":"\/\/drfuittf5cya9.cloudfront.net\/123\/small\/1911802897.jpg"
}
]
}
In my angular code I have written:
<div ng-controller="productImages">
<div ng-repeat="product in products">
{{product.image_id}}
</div>
</div>
When I run this the ng-repeat div gets repeated twice but product.image_id does not show up. If I do {{product}} instead or {{product.image_id}} I get the whole JSON printed.
How do I print this JSON in angularJS? Also, How do I get Product_1, Product_2 printed?

Your object Product_1 seems to be an array which in turn has images.
I think you will need nested for loops to display the images

You try to repeat over the properties of an object.
Accourding to the documentation here you'll have to use
<div ng-repeat="(key, value) in myObj"> ... </div>
each property of your object is an array so I think that something like:
<div ng-repeat="(key, value) in myObj">
<div ng-repeat= "product in value">
{{product.image_id"}}
</div>
</div>
should do the trick

Use two loops for this as:
angular.module('app',[]).controller('mainCtrl', function($scope){
$scope.products = {
"Product_1":[
{ "image_id":"12469",
"name":"My Product 1 - Variety 1",
"url":"\/\/mystorefront.net\/120\/small\/1911791794.jpg"
},
{
"image_id":"12470",
"name":"My Product 1 - Variety 2",
"url":"\/\/drfuittf5cya9.cloudfront.net\/121\/small\/1911802897.jpg"
}
],
"Product_2":[
{ "image_id":"122349",
"name":"My Product 2 - Variety 1",
"url":"\/\/drfuittf5cya9.cloudfront.net\/122\/small\/1911791794.jpg"
},
{
"image_id":"123470",
"name":"191123897.jpg",
"name":"My Product 2 - Variety 2",
"url":"\/\/drfuittf5cya9.cloudfront.net\/123\/small\/1911802897.jpg"
}
]
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app' ng-controller='mainCtrl'>
<div ng-repeat="product in products">
<div ng-repeat="item in product">
{{item.image_id}}
</div>
<hr/>
</div>
</div>

Your JSON syntax is incorrect. If I understand correctly, each of our product has several varieties. It should be as follows:
{
"Products": [
{
"Product": [
{
"image_id": "12469",
"name": "My Product 1 - Variety 1",
"url": "//mystorefront.net/120/small/1911791794.jpg"
},
{
"image_id": "12470",
"name": "My Product 1 - Variety 2",
"url": "//drfuittf5cya9.cloudfront.net/121/small/1911802897.jpg"
}
]
},
{
"Product": [
{
"image_id": "122349",
"name": "My Product 2 - Variety 1",
"url": "//drfuittf5cya9.cloudfront.net/122/small/1911791794.jpg"
},
{
"image_id": "123470",
"name": "My Product 2 - Variety 2",
"url": "//drfuittf5cya9.cloudfront.net/123/small/1911802897.jpg"
}
]
}
]
}
And you HTML should be:
<div ng-controller= "Products">
<div ng-repeat= "for oneproduct in Products">
<div ng-repeat="for variety in oneproduct">
{{variety.image_id"}}
</div>
</div>
</div>
Not tested this though...

You can't iterate on the object productImages because it's not an array.
You can iterate the objects "Product_1" and "Product_2".
If you want iterate the object productImage you have to write it ad an array.

Related

Angular ng-if any child contains

I'm trying to conditionally show and hide columns based on the data returned, if the data set contains any objects meeting conditions.
Here is a sample of the data returned from my search results
[
{
"id": "typeahead-241-1091-option-0",
"label": "Android Home Page",
"model": {
"type": "link",
}
},
{
"id": "typeahead-241-1091-option-1",
"label": "Google",
"model": {
"type": "link",
}
},
{
"id": "typeahead-241-1091-option-2",
"label": "Forgotten Google Play Password",
"model": {
"type": "kb",
}
}
]
Now I'm presenting the data in columns, based on the type.
<div class="flexitem">
<h4>External Links</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'link'">{{match.label}}</div>
</div>
<div class="flexitem">
<h4>Knowledge Base</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'kb'">{{match.label}}</div>
</div>
<!-- the below has no results. I want it hidden altogether
currently it shows the <h4>Products</h4> with nothing below it-->
<div class="flexitem">
<h4>Products</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'product'">{{match.label}}</div>
</div>
What I need to accomplish is putting conditions on the flexitem divs altogether to only show if there are results for that type. So if there are no results with the type == 'product', then don't even show that div. A ng-if on that row would work, but what will be the best way to cycle through all of the children of match to determine if there is a result? indexOf doesn't work through children arrays.
Put the logic on the angular side using Array.filter to separate arrays;
Angular controller:
$scope.linkMathches = $scope.matches.filter(function(m){
return m.model.type === 'link'
});
$scope.kbMathches = $scope.matches.filter(function(m){
return m.model.type === 'kb'
});
HTML:
<div class="flexitem" ng-if="linkMathches.length">
<h4>External Links</h4>
<div ng-repeat="match in linkMathches">
{{match.label}}
</div>
</div>
<div class="flexitem" ng-if="kbMathches.length">
<h4>Knowledge Base</h4>
<div ng-repeat="match in kbMathches">
{{match.label}}
</div>
</div>
Going further for dynamic values in model.type:
Angular controller:
$scope.typeMatches = {
link: {title: 'External Links', matches: []},
kb: {title: 'Knowledge Base', matches: []},
product: {title: 'Products', matches: []}
};
$scope.matches.forEach(function(match){
$scope.typeMatches[match.model.type].matches.push(match);
});
HTML:
<div class="flexitem"
ng-if="value.matches.length"
ng-repeat="(key,value) in typeMatches">
<h4>{{value.title}}</h4>
<div ng-repeat="match in value.matches">
{{match.label}}
</div>
</div>

Fetching information from nested JSON based on unique fields using AngularJS

I have a json as following.
{
"id":14,
"discussion":8,
"parent":0,
"userid":2,
"subject":"communication skill discussion 2",
"message":"<p>hi all to communication discussion 2 </p>",
"children":[
24,
16,
15
]
},
{
"id":15,
"discussion":8,
"parent":14,
"userid":2,
"subject":"Re: communication skill discussion 2",
"message":"<p>hiiiiiiiiii</p>",
"children":[
25,
23
],
},
{
"id":23,
"discussion":8,
"parent":15,
"userid":2,
"created":1461562317,
"modified":1461562317,
"mailed":0,
"subject":"Re: communication skill discussion 2",
"message":"<p>helloooo</p>",
"children":[
],
}
I want first fetch the details whose Ids matches with the elments in children array
such as for id:14 there are 3 children 24,16,15.Then the control should go directly to id:15 and fetch details of id:15.Again id has children eg. consider id:23 which has no children and will directly print the message.
Please guide me how will I achieve this using ng-repeat of angular ?
Refer to the demo.
Please find the code below:
HTML:
<div ng-app="app" ng-controller="test">
<div ng-repeat="(key,value) in data">
{{key + 1}}) --
<span ng-if="value.children.length > 0">
{{value.children}}
</span>
<span ng-if="!(value.children.length > 0)">
No children found!!
</span>
</div>
</div>
JS:
var app = angular.module('app', []);
app.controller('test', function($scope) {
$scope.data = [{
"id": 14,
"discussion": 8,
"parent": 0,
"userid": 2,
"subject": "communication skill discussion 2",
"message": "<p>hi all to communication discussion 2 </p>",
"children": [
24,
16,
15
]
}, {
"id": 15,
"discussion": 8,
"parent": 14,
"userid": 2,
"subject": "Re: communication skill discussion 2",
"message": "<p>hiiiiiiiiii</p>",
"children": [
25,
23
],
}, {
"id": 23,
"discussion": 8,
"parent": 15,
"userid": 2,
"created": 1461562317,
"modified": 1461562317,
"mailed": 0,
"subject": "Re: communication skill discussion 2",
"message": "<p>helloooo</p>",
"children": [
],
}];
});
UPDATE: As per the request
Demo
HTML:
<div ng-app="app" ng-controller="test">
<div ng-repeat="(key,value) in data">
[{{key + 1}}] --
<div ng-if="value.children.length > 0">
<div ng-repeat="item in value.children">
<span>{{item}}</span> <span class="green" ng-bind-html="getMessage(item)"></span>
</div>
</div>
<span ng-if="!(value.children.length > 0)">
No children found!!
</span>
<br />
</div>
</div>
JS:
$scope.getMessage = function(itemId) {
var flag = true;
var msg;
angular.forEach($scope.data, function(value, key) {
if (flag && value.id == itemId) {
flag = false;
msg = value.message;
}
});
return $sce.trustAsHtml(msg);
}
CSS:
.green {
color: green;
}
Use ng-repeat to display the records.
<ul ng:controller="Cntl">
<li ng:repeat="item in data">
{{item.subject}}: Parent
<ul>
<li ng:repeat="child in item.children">{{child}} : Children
</li>
</ul>
</li>
This is one of the way to display in html. Based on your page design ng-repeat will change.
You can use lodash or underscore _.where:
<div ng:controller="Cntl">
<div ng:repeat="item in data">
{{item.subject}}<br/>
Children
<div ng:repeat="child in item.children">{{_.where(data, {id:child});}}
</div>
</div>
First you need to restructure your json into a tree structure. May be you want to have a look at this post. Then you have to recursively add templates

Render a directive with two datasources

My problem is a bit complex, so i will try to explain it as detailed as possible.
I have a directive in a SPA that render their components based on a JSON data that i'm getting from an API. Based on the elements and their types (the JSON is an array of different objects) i'm rendering every object in an specific directive:
Objects Type 1: Renders in a Directive Type 1.
Objects Type 2: Renders in a Directive Type 2.
Objects Type 3: Renders in a Directive Type 3.
Directives Type 1-2-3 are contained in the parent directive and every directive has different controls (select, checkbox). This is a very simple Sketch:
And the "sub-directives":
I'm rendering my elements as follows (Container directive):
<div ng-repeat="element in elementList | customFilter:itemsType1">
<div class="line"></div>
<div class="form-group">
<directivetype1 itemdata="element" modeldata="data"></directivetype1>
</div>
</div>
<div ng-repeat="element in elementList | customFilter:itemsType2">
<div class="line"></div>
<div class="form-group">
<directivetype2 itemdata="element" modeldata="data"></directivetype2>
</div>
</div>
...
And this is the Directive 1 code:
<div class="container-fluid">
<div class="form-group">
<div class="col-xs-6 col-sm-3">
<div class="checkbox">
<label><input type="checkbox"/>{{itemdata.metadata.description}}</label>
</div>
</div>
<div class="col-xs-6 col-sm-3">
<label>Option</label>
<select class="form-control" ng-model="" ng-options="list.id as list.label for list in item.optionData"></select>
</div>
</div>
</div>
My problem goes when i try to attach the model to every element rendered, because of:
The model data comes from another API, in another structure.
I'm iterating the list of controls with ng-repeat, but, when i pass the model data to the sub-directive i'm passing all the possible data (as Array) and i'm not being capable of filter and know what object in that array belongs to an specific view element.
The data has the following structure:
View data:
[
{
"elementA": {
"metadata": {
"id": "001",
"subId": "016",
"description": "Element 1"
},
"optionData": [
{
"id": "5",
"label": "Option 1"
},
{
"id": "6",
"label": "Option 2"
},
{
"id": "7",
"label": "Option 3"
}
]
}
},
{
"elementB": {
"metadata": {
"id": "002",
"subId": "024",
"description": "Element 2"
},
"optionData": [
{
"id": "1",
"label": "Option 1"
},
{
"id": "2",
"label": "Option 2"
},
{
"id": "3",
"label": "Option 3"
}
]
}
}
]
Model data:
[
{
"metadata": {
"id": "002",
"subId": "024",
"description": "Element 2",
"selected": "1"
},
...(Some other data belonging to the model)
},
{
"metadata": {
"id": "001",
"subId": "016",
"description": "Element 1",
"selected": "5"
},
...(Some other data belonging to the model)
},
...
]
As you can see, the only way to correlate both models is with id and subId Fields in the metadata object (because the metadata itself can vary having more or less fields).
QUESTION
How can i filter my model object, based on the view object? My goal is to get the model object that correlates to the view object and pass it to the sub-directive for setting it as the model of the control that i'm rendering at that point.
EDIT:
As cmw pointed out, i've coded a function to correlate every model object with their respective view object, but that object is not reflected in the directive scope. itemdata and modeldata are passed to the directive using a bi-directional scope ('='). I think (but i'm not entirely sure) that, when i pass a function to modeldata the directive is not being capable of setting the returned object. The solution that i've coded based on the cmw answer is as follows:
Directive:
<directivetype1 itemdata="element" modeldata="getModelObject(data)"></directivetype1>
JS (coded in the Ctrl of the parent):
$scope.getModelObject = function(element){
var id = typeof element.metadata === 'undefined' ? null : element.metadata.id;
var subid = typeof element.metadata === 'undefined' ? null : element.metadata.subid;
var modelElement = null;
for (var i = 0; i < $scope.data.length; i += 1){
element = $scope.data[i];
if (modelElement.metadata.id === id && modelElement.metadata.subid === id) return element;
}
return null;
};
But when i try to work in the directive with modeldata i see "null" in FF/Chrome Console.
Any guideline to know what's happening?
Thanks.
EDIT 2:
I've added a version of my code here: http://plnkr.co/edit/xjp1l3PuWczdqYf5LP8q?p=preview. Sadly, in that Plunkr it works as expected but my code does not (i'm expecting to see the output of <h1>{{modeldata}}</h1>). I'm comparing the two versions to see any difference (note that i've included the same AngularJS version that i'm using in my project).
As you've pointed out, I believe the key is simply to make use of the id and subId properties on the meta object.
Something like this would probably work...
<div ng-repeat="element in elementList | customFilter:itemsType1">
<div class="line"></div>
<div class="form-group">
<directivetype1 itemdata="element" modeldata="modelDataFor(element)">
</directivetype1>
</div>
</div>
Then, in your controller, define a function like the following...
$scope.modelDataFor = function (element) {
var id = element.meta.id,
subId = element.meta.subId,
curr;
for (var i = 0; i < $scope.data.length; i += 1) {
curr = $scope.data[i];
if (curr.meta.id === id && curr.meta.subId === subId) {
return curr;
}
}
return null;
}
This seems like the most natural place to pluck out the relative data model object to pass into your nested directives.

Readout JSON data in different divs

I am absolutely new at this. The plan is to show the data from the JSON file in different divs, because I want to style the divs in different ways.
1) First I want to read out a single line of my JSON, for example:
The HTML:
<div>
<div data-filter="EX_01_Dates"></div>
<div data-filter="EX_01_Name"></div>
<div data-filter="EX_01_City"></div>
</div>
And the JSON:
var data={"events":[
{
"id": EX_01,
"Name":"Event 1",
"City":"City 1",
"Dates":"13-09-2015",
},
]}
2) Second, I want this with different data blocks.
var data={"events":[
{
"id": EX_01,
"Name":"Event 1",
"City":"City 1",
"Dates":"13-09-2015",
},
{
"id": EX_02,
"Name":"Event 2",
"City":"City 2",
"Dates":"15-09-2015",
}
]}
Thats my jsfiddle. Hope someone can help me?
Something like this?
var data={"events":[
{"id": "EX_01", "Name":"Event 1", "City":"City 1", "Dates":"13-09-2015" },
{"id": "EX_02", "Name":"Event 2", "City":"City 2", "Dates":"15-09-2015" }
]};
data["events"].forEach(function(elem) {
for(var key in elem) {
var filter = [elem["id"], "_", key].join("");
$("div[data-filter='" + filter + "']").text(elem[key]);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<div data-filter="EX_01_Dates"></div>
<div data-filter="EX_01_Name"></div>
<div data-filter="EX_01_City"></div>
</div>
<div>
<div data-filter="EX_02_Dates"></div>
<div data-filter="EX_02_Name"></div>
<div data-filter="EX_02_City"></div>
</div>
Read about Array forEach and for...in to learn how they work!
I highly recommend you use jsrender for this purpose, there are alot of great articles about it out there. I found the article below very helpful if you dont understand http://www.jsviews.com hope this helps..
https://msdn.microsoft.com/en-us/magazine/hh882454.aspx
First of all it is not clear what exactly you are doing here.
<div id="EX_01">
<div data-filter="EX_01_Dates"></div>
<div data-filter="EX_01_Name"></div>
<div data-filter="EX_01_City"></div>
</div>
<div id="EX_02">
<div data-filter="EX_02_Dates"></div>
<div data-filter="EX_02_Name"></div>
<div data-filter="EX_02_City"></div>
</div>
your javascript code which is now jquery added
var data={"events":[
{
"id": EX_01,
"Name":"Event 1",
"City":"City 1",
"Dates":"13-09-2015",
},
{
"id": EX_02,
"Name":"Event 2",
"City":"City 2",
"Dates":"15-09-2015",
}
]}
$("#EX_01").find("div:nth-child(1)").html(data.events[0].Dates);
$("#EX_01").find("div:nth-child(2)").html(data.events[0].Name);
$("#EX_01").find("div:nth-child(3)").html(data.events[0].City);
$("#EX_02").find("div:nth-child(1)").html(data.events[1].Dates);
$("#EX_02").find("div:nth-child(2)").html(data.events[1].Name);
$("#EX_02").find("div:nth-child(3)").html(data.events[1].City);
you can work around more for dynamic creation or selection of html elements

Targeting nested array in ng-repeat

Can someone please advise me what I'm doing wrong here?
I am retreiving some data and injecting in to a controller as 'productInfo'.
I can load in the data fine but when I want to target specific values within a ng-repeat, I'm not getting the desired result. The best I'm getting is the last set of data i the JSON.
I'm getting the JSON from the server and can change the formatting if required. I'm just starting out with Angular so apologies if there is a simple answer.
HTML:
<div ng-controller="ProductStandardCtrl">
<p>Item:</p>
<article ng-repeat="item in items">
<img ng-src="{{item.img}}" class="logo" alt="">
<h4>{{item.title}}</h4>
</article>
</div>
JSON:
{
"description":"Lorem Ipsum",
"headline":"Promotion headline",
"items":{
"Standard":
{"img":"http://placehold.it/303x152",
"title":"Standard Product 1"
},
"Standard":
{"img":"http://placehold.it/303x152",
"title":"Standard Product 2"
},
"Standard":
{"img":"http://placehold.it/303x152",
"title":"Standard Product 3"
}
}
}
Thanks
The items property on your json isn't an Array, so you can't iterate over it.
The desired format should be like this:
{
"description":"Lorem Ipsum",
"headline":"Promotion headline",
"items":[
{
"img":"http://placehold.it/303x152",
"title":"Standard Product 1"
},
{
"img":"http://placehold.it/303x152",
"title":"Standard Product 2"
},
{
"img":"http://placehold.it/303x152",
"title":"Standard Product 3"
}
]
}
You have identical keys inside items. The keys must be unique:
"items":{
"Standard":{
..
},
"Standard":{
..
},
"Standard":{
..
}
}
should be something like
"items":{
"Standard1":{
..
},
"Standard2":{
..
},
"Standard3":{
..
}
}

Categories

Resources