Looping over multiple json arrays with Angular - javascript

I have a large JSON file structured like the following which I'm trying to loop over in Angular:
{
"subject1":[
{
"title":"titlehere",
"info":"infohere."
}],
"subject2":[
{
"title":"titlehere",
"info":"infohere."
}],
"subject3":[
{
"title":"titlehere",
"info":"infohere."
}]
}
I want my page to grab the key for each 'category' and then the display the title underneath it. I'm able to get the key to display but I can't seem to figure out how to grab the string for each title. This is what I have in my HTML:
<div ng-repeat="(key, value) in faqs">
<h3>{{ key }}</h3>
<ul>
<li>{{ value }}</li>
</ul>
</div>
I'm not sure what I should be using instead of {{ value }} which grabs nothing but the entire JSON file as a string. I tried {{ value.title }} and still had no luck.
Any suggestions?

Use {{ value[0].title }}
your code be
<div ng-repeat="(key, value) in faqs">
<h3>{{ key }}</h3>
<ul>
<li ng-repeat="val in value">{{ val.title }}</li>
</ul>
</div>

Related

How to know if an insertion was successfull in a MongoDB Collection with Meteor.JS (inside the Template)

The situation
Let's break this question down to a simple todo list of which the entries are listed in a \li:
//main.html
<ul>
{{ #each listEntries }}
<li class="item">
{{ title }}
</li>
{{ /each }}
</ul>
Serverside:
//main.js
TodoCollection = new Mongo.Collection('todo_collection');
Now I am calling manually from the console in the client:
TodoCollection.insert({title: 'My first entry'});
Up to this point everything's fine.
Now meteor.JS works asynchronously which means that the changes that are made in the client also have effect on the DOM right away without knowing if the database insertion was successfull or not. If not, the DOM Element will be removed again (so first meteor inserts the new <li>, then it removes it again if insertion failed).
How can you get the information from meteor that something comes actually from the database?
What I need:
//main.html
<ul>
{{ #each listEntries }}
<li class="item">
{{ title }}
{{ #if isInDatabase }}
- i am actually stored!
{{ /if }}
</li>
{{ /each }}
</ul>
You can use the callback of the insert method of the collection. The callback is called with the error (null if there is none) and the object Id that was stored in the database
Below you can see the code to test this:
html:
<head>
<title>simple</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{>test}}
</body>
<template name="test">
<ul>
{{#each item in list}}
<li>{{item.name}}</li>
{{/each}}
</ul>
{{#if insertResult}}
<div class="insert_result">{{insertResult}}</div>
{{/if}}
{{#if insertError}}
<div class="insert_error">{{insertError}}</div>
{{/if}}
<form>
<input type="text" name="name" />
<input type="submit" value="Add" />
</form>
</template>
Javascript:
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
collection = new Mongo.Collection('collection');
if (Meteor.isClient) {
Template.test.onCreated(function () {
this.insertResult = new ReactiveVar();
this.insertError = new ReactiveVar();
});
Template.test.helpers({
list() {
return collection.find();
},
insertResult() {
return Template.instance().insertResult.get();
},
});
Template.test.events({
'submit form'(event, instance) {
event.preventDefault();
collection.insert({
name: event.target.name.value
},function(err,result) {
if (err) {
instance.insertError.set(err);
instance.insertResult.set(null);
} else {
instance.insertResult.set(result);
instance.insertError.set(null);
}
});
},
});
}
As you can see in the previous answer, it is quite cumbersome in Meteor to know what causes a reactive update.
I would suggest a different approach: Don't insert on the client. Make a Meteor.call() to a server method which does the insert, and then let the client update reactively. Then you are always sure that what you see on the screen is actually in the database.
I think I found the most trivial solution myself:
Adding a hook on server-side that will add the date of creation with obj.onCreated = new Date(); helps identifying that it came from the server because this will not exist on the client.
{{#each item}}
{{ #if item.onCreated }}
<li class="success-db">{{name}}</li>
{{ else }}
<li class="pending-db">{{name}}</li>
{{ /if }}
{{/each}}
(Please do not hesitate to improve this answer if you find it contradictory to how Meteor.JS works)
If you want to show the data which title exist then you can write the code like this.
<ul>
{{ #each listEntries }}
<li class="item">
{{ title }}
{{ #if title }}
- i am actually stored!
{{ /if }}
</li>
{{ /each }}
</ul>

How do I display json data in HTML page from json string stored in localstorage

I have data returned from laravel in the following format. I store this in localstorage to be used by the users once he logs in.
I am using angular in frontend, this is how I store it
$http.get($scope.url).success(function(redata){
localStorage.setItem('session', JSON.stringify(redata));
$scope.fulldata = JSON.parse(localStorage.getItem("session"));
});
This is the json data
{
"tweets":[
{"id":"3","uid":"15","tweets":"Molly's first tweet"},
{"id":"4","uid":"15","tweets":"molly again here, second tweet"},
{"id":"5","uid":"15","tweets":"third tweet"}
],
"users":[
{"id":"1","name":"rob","email":"rob#gmail.com","password":""},
{"id":"2","name":"bob","email":"bob#gmail.com","password":""}
]
}
I am able to display the json using angular ng-repeat
<p ng-repeat="data in fulldata">
{{ data }}
</p>
But if I need to just display the content of tweets i.e "tweets" field of tweets, how do I do that.
I tried :-
<p ng-repeat="data in fulldata">
{{ data.tweets.tweets }}
</p>
but this did not work.
Thanks
you have to loop on tweets array.
<p ng-repeat="data in fulldata.tweets">
{{ data.tweets }}
</p>
You are looping through fulldata, which has just single tweets element. you need to loop through fulldata.tweets
<p ng-repeat="data in fulldata.tweets">
{{ data.tweets}}
</p>
or if you need to loop through all fulldata for all tweets
<div ng-repeat="data in fulldata">
<p ng-repeat="tweet in data.tweets">
{{ tweet.tweets }}
</p>
</div>
since the inner JSON is nested so you need two nested ng-repeat
<div ng-repeat="data in fulldata">
<p ng-repeat="tweets in data.tweets">
{{ tweets.tweets }}
</p>
</div>
<p ng-repeat="tweet in fulldata.tweets">
{{ tweet.tweets }}
</p>
This is what you want to do, no need for nested ng-repeats unless you specifically want that.

Manipulating data in angularjs/javascript

I have a an array of objects like this in angular:
$scope.data = [
{name:"John", group:"a"},
{name:"David", group:"a"},
{name:"Tom", group:"b"},
];
I want to present this data as something like this (in a template):
<h2>group a</h2>
John<br/>
David<br/>
<h2>groub b</h2>
Tom<br>
How would you suggest to do this? How can I go from the structure at the beginning to the structure at the end?
You could use grouby filter that would do group for you on basis of group property
Markup
<div ng-repeat="(key, value) in data | groupBy: 'group'">
<h1>group {{ key }}</h1>
<div ng-repeat="person in value">
{{ person.name }}
</div>
</div>

Having trouble repeating correct items with nested ng-repeat and ng-if

I have the following html:
<div ng-repeat="tab in tabs" ng-if="tabIsActive(tab, $index)">
<ul ng-repeat="section in tab.sections">
<h2 ng-class="productTitle" ng-repeat="child in section.children" ng-if="sideTabIsActive(section, $index)">
<img ng-src="{{ child.productImageURL }}"/>
<li>{{ child.title }}</li>
</ul>
</div>
This is what the "tabs" javascript object looks like:
My desired output is the subcategory titles(e.g. children0.title) and image(e.g. children0.productImageURL) listed for each section when that section is selected.
Example desired output:
When Analytical Balances is clicked
(ML image) //which is section0.child0.productImageURL
ML //which is section0.child0.title
(XS image) //which is section0.children1.productImageURL
XS //which is section0.child1ren.title
Currently, I display this:
When Analytical Balances is clicked:
(ML image) //which is section0.children0.productImageURL
ML //which is section0.children0.title
(XPE image) //which is section1.children0.productImageURL
XPE //which is section1.children0.title
How can I list both children (and the associated image) for each section based on which section is selected (selectedSideIndex)?
In addition to the above HTML, here is relevant HTML and javascript that I use in my attempt to achieve the desired output:
$scope.toggleSideSelect = function(ind){
$scope.selectedSideIndex = ind;
}
$scope.sideTabIsActive = function (tab, $index) {
var selectedIndexTest = $scope.selectedSideIndex
return $index==$scope.selectedSideIndex;
}
<div ng-repeat="tab in tabs" ng-if="tabIsActive(tab, $index)">
<ul ng-repeat="section in tab.sections" ng-click="toggleSideSelect($index)">
<li>{{ section.title }}</li>
<ul ng-repeat="child in section.children">
<li>{{ child.title }}</li>
</ul>
</ul>
</div>
You were almost there :)
What you need to do is this:
<div ng-repeat="tab in tabs" ng-if="tabIsActive(tab, $index)">
<ul ng-repeat="section in tab.sections" ng-init="sectionIndex = $index">
<h2 ng-class="productTitle" ng-repeat="child in section.children" ng-if="sideTabIsActive(section, sectionIndex)">
<img ng-src="{{ child.productImageURL }}"/>
<li>{{ child.title }}</li>
</ul>
</div>
This way, using the ng-init="sectionIndex = $index" you are saving the $index of the section and can use it on the nested ng-repeat. It's also possible to use $parent.$index but I wouldn't recommend it since the structure might change and you will be left with a bug.
This way, you can call ng-if="sideTabIsActive(section, sectionIndex)" using the index of the section, and only your active section's children will get to show.
Edit: you should probably change the signature of
$scope.sideTabIsActive = function (tab, $index)
to
$scope.sideTabIsActive = function ($index)
Since you're not actually using the tab in the function. (And if you do, don't forget to change the call to that function from the view as well)

Handlebars parse error on #each

I'm returning the following JSON object
{"status":"success",
"valmessage":"Your message has been sent successfully.",
"postcontent":{
"post_author":1,
"post_recipient":"1",
"post_title":"handle test 2",
"post_type":"wp_inbox_msg",
"post_content":"<p>giving it another go.<\/p>\n"},
"postmeta":{
"postid":410,
"postdate":"Monday, March 17th, 2014",
"author":"admin"},"replies":null,
"Formerrors":[]
}
and I'm getting the following error inside my handlebars template :
Uncaught Error: Parse error on line 23:
...replies}} {{ #each replies }
----------------------^
Expecting 'ID', 'DATA', got 'INVALID'
inside my tempalte I'm doing the following :
{{#if replies}}
{{ #each replies }}
<li>
<figure class="reply-author-img">
<img alt="" src="{{ avatar }}" height="96" width="96">
</figure>
<div class="replycontentwrap">
<div class="reply-from">
<p class="reply-author">
<strong>{{ fullname }}</strong>
<span>{{ nickname }}</span>
</p>
<span class="replydate">{{ reply_date }}</span>
</div>
<div class="reply-content">{{ reply_content }}</div>
</div>
</li>
{{ /each }}
{{/if}}
Replies is currently Null but it should be returning a set of objects when there are replies to the message, How would be the best way to 1) get this working and 2) approach this kind of data structure with handlebars.js ?
The error you are getting is a result of the fact that you have a space before the '#each' and '/each', so make it:
{{#each replies}}
/* each stuff */
{{/each}}
You can also directly use as below to reduce complexity, also you get good understanding if there are multiple each blocks.
{{#replies}}
{{this}}
{{/replies}}
This method is parallel to #each and can iterate key value if it is object, otherwise array index and object(value)

Categories

Resources