Loop over JSON with Handlebars JS and Ember JS - json

I am learning Ember JS and Handlebars JS so I am very new to this. I am having an issue trying to loop through the following JSON.
Here is my JSON:
{
"sgt_rules": {
"app_tags": {},
"city": [],
"consumer_tags": [],
"device_tags": {
"os": [
"ios"
]
},
"participation": null,
"registration": null
}
}
This is my handlebars template:
<h2>{{controllers.segment.sgt_name}}</h2>
<script type="text/x-handlebars" data-template-name="pull">
<ul>
<li>{{getsegmentrules}}</li>
</ul>
</script>
The ember helper function in case I need to modify it:
import Ember from 'ember';
var controller = Ember.Controller.extend({
needs: ['segment'],
getsegmentrules: function () {
var model = this.get('content').get('sgt_rules');
}.property()});
export default controller;
I have tried this but it doesn't work:
<script type="text/x-handlebars" data-template-name="pull">
<ul>
<li>{{controllers.segment.sgt_rules}}</li>
{{#each segment in controllers.segment.sgt_rules}}
<li>App Tags: {{segment.app_tags}} <br /> City: {{segment.city}} <br />
Consumer Tags: {{segment.consumer_tags}} <br /> Device Tags: {{segment.device_tags}} <br />
Participation: {{segment.participation}} <br /> Registration: {{segment.registration}} <br />
<ul>
{{#each obj in segment.device_tags}}
<li>{{obj.os}}</li>
{{/each}}
</ul>
</li>
{{/each}}
</ul>
</script>
What am I missing here? Do I need to write any helper function as well?

shouldn't you return a value here?
getsegmentrules: function () {
var model = this.get('content').get('sgt_rules');
return model;
}.property()});
Also where are you setting the JSON data?

Related

How to create a bullet list from parsed dynamic object

So I have a JSON string foo_json_string:
[{"foo_name":"foo_value"},{"foo_name1":"foo_value1"}]
that I want to parse and show as HTML list.
I used the following approach:
<ul>
<li v-for="item in JSON.parse(foo_json_string)" v-bind:key="item.id">
{{`${item.name} = ${item.value}`}}
</li>
</ul>
This doesn't work. Most likely because item.name and item.value don't exist but I am not sure how to fix that. Any suggestions?
Maybe, you mean like this ?
var respond = [{"foo_name":"foo_value"},{"foo_name1":"foo_value1"}];
$.each(respond, function(k, v){
console.log(v);
$.each(v, function(k1, v1){
$('#out').append('<li>'+v1+'</li>');
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="out"></ul>
You need to access the key of the parsed Object. Use Object.keys() method for getting the key. There is the working snippet below.
new Vue({
el: '#app',
data: {
foo_json_string: '[{"foo_name":"foo_value"},{"foo_name1":"foo_value1"}]',
},
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<ul v-for="item in JSON.parse(foo_json_string)">
<li v-for="key in Object.keys(item)">
{{`${key} = ${item[key]}`}}
</li>
</ul>
</div>

How to append list from JSON array?

I want for loop or for each or both codes for learning both ways to make the format like,I want the to acccess the id "list" to append li.
HTML
<div id="list">
<ul>
<li>Mainland China</li>
<li>Hotel Park Inn</li>
....
</ul>
</div>
HTML
<html>
<head>
</head>
<body>
<input data-inline="true" id="submit" type="submit" value="Go">
</body>
</html>
JS
$(function() {
$("#submit").click(function() {
var data='{"restaurant": {"results": [{"name": "The Astor"},{"name": "Mainland China"},{"name": "Bhojohori Manna"},{"name": "6 Ballygunge Place"},{"name": "Zaranj"},{"name": "Hotel Park Inn"},{"name": "Oh! Calcutta"},{"name": "Red Hot Chilli Pepper"},{"name": "Chinoiserie"}]}}';
var json = JSON.parse(data);
alert(json.restaurant.results.length);
alert(json.restaurant.results[0].name);
});
});
I think you just need to add below line inside click function.
var list = $('#list');
jsonData = JSON.parse(data);
jsonData.restaurant.results.forEach(function(i){
list.append('<li>'+i.name+'</li>');
});
EDIT:-
var jsonData = JSON.parse(data);
jsonData.restaurant.results.forEach(function(i){
$('ul').append('<li>'+i.name+'</li>');
});

Angular Js get Json not working

I'm trying to make a simple angular app which reads json data , but in response I'm only getting "," not data.Any pointers where I m going wrong ? I have attached index.html and abc.json file that i m keepingat server
PFB the code .
HTML:
<body ng-app="sampleApp" ng-controller="ctrl1">
Name:<input type="text" ng-model="name">
<ul>
<li ng-repeat="student in students | filter:name">{{student.name +","+student.empNo}</li>
</ul>
Name:<input type="text" ng-model="newname">
EmpNo:<input type="text" ng-model="newemp">
<input type="button" value="AddMe" ng-click="add()"/>
<div>
<div ng-view></div>
</div>
Javascript:
var x=angular.module('sampleApp',[])
.factory("simpleFactory",function($http){
var factory={};
factory.getStudents=function(){
return $http.get("abc.json");
}
return factory;
})
.controller("ctrl1",function($scope,simpleFactory){
$scope.students=simpleFactory.getStudents();
$scope.add=function(){
$scope.students.push(
{
name:$scope.newname,empNo:$scope.newemp
}
)
}
})
abc.json
[
{"name":"jack","empNo":"1"},
{"name":"Red","empNo":"2"},
{"name":"Jill","empNo":"3"}
]
getStudents is asynchronous. You should retrieve and assign students through the callback handler.
.factory("simpleFactory",function($http){
var factory={};
factory.getStudents = $http.get("abc.json");
return factory;
})
.controller("ctrl1",function($scope,simpleFactory){
simpleFactory.getStudents().then(function(result) {
$scope.students= result.data;
});
...
})
Nearly right. getStudents in fact returns you a 'Promise', not the data itself. You have to use that Promise to get your data:
simpleFactory.getStudents().then(function(data) {
$scope.students=data
// $scope.students=data.data // you may need this given your feedback
});

get nested JSON object in angular js

I'm having a AngularJS spa and want to fetch files from a JSON, which works good so far.
var app = angular.module("MyApp", []);
app.controller("TodoCtrl", function($scope, $http) {
$http.get('todos.json').
success(function(data, status, headers, config) {
$scope.posts = data;
}).
error(function(data, status, headers, config) {
alert("Error");
});
});
and bind it to repeat a list.
<ul ng-repeat="post in posts">
<li>
<b>Name : </b> {{post.name}} <br>
<b>Adress/street :</b> {{post.address.street}}
</li>
</ul>
my problem ist, what if I have nested another object inside the JSON:
"adress": [
{
"street": "somewhat street",
"town": "somewhat town"
}]
My attempt post.adress.street does not work. Any suggestions?
Since address is an array, you have 2 options.
First option:
Use the array notation to access only one of the items in the array. For example:
<ul ng-repeat="post in posts">
<li>
<b>Name : </b> {{post.name}} <br>
<b>Adress/street :</b> {{post.address[0].street}}
</li>
</ul>
Second option:
Iterate over all the address items using another ng-repeat:
<ul ng-repeat="post in posts">
<li>
<b>Name : </b> {{post.name}} <br>
<div ng-repeat="address in post.address">
<b>Adress/street :</b> {{address.street}}
</div>
</li>
</ul>

Best way to implement a tabpanel in ember?

I'm new to ember and trying to build a Ember driven web application. I've read various tuts and studies several examples. The basic concepts are clear but now I'am stuck on trying to implement a tabpanel. My approach is as follows:
View
Configurator.TabPanelView = Ember.View.extend({
classNames: ['tabPanel'],
templateName: 'tabPanel'
});
Template
<script type="text/x-handlebars" data-template-name='tabPanel'>
<div class='tabHead'>
<ul>
{{#each tabViews}}
<li {{action "{{this.actionName}}" target="{{this.value}}"}} >{{this.title}}</li>
{{/each}}
</ul>
<div class="tab-content">{{outlet}}</div>
</div>
</script>
Usage in App
var tab= Configurator.TabPanelView.create({
classNames: ['assortment'],
tabViews: [{ title: 'First', value:'Foo', actionName: 'firstTab' },{title: 'Second', value:'Foo', actionName: 'secondTab' }],
firstTab: Ember.View.extend({
templateName: 'first'
}),
secondTab: Ember.View.extend({
templateName: 'second'
})
});
tab.appendTo("body");
The TabTemplate is rendered correctly but if I try to click on the li-elements following error is thrown
Uncaught Error: assertion failed: Target <(subclass of
Ember.View):ember217> does not have action {{this.actionName}}
I'm also curious if I should use a router to implement tabbing. But as far as i can see routers act on application level and are intended to be used in single UI-compos.
The problem is in your template:
<li {{action "{{this.actionName}}" target="{{this.value}}"}} >{{this.title}}</li>
AFAIK, actions can't be bound, so when you write this, it tries to call the method {{this.actionName}} instead of firstTab, for example.
I think this is a typical example where you should use a Ember.CollectionView with an itemViewClass which has the click method, i.e.:
App.MyCollectionView = Ember.CollectionView.extend({
tagName: 'ul',
templateName: 'the-template-name',
itemViewClass: Ember.View.extend({
click: function() {
var actionName = this.get('content.actionName'),
target = this.get('controller.target');
target.send(actionName);
}
})
});
The code above is surely not right, but the idea is here.
But I think the Router is the right way to do that. I suggest you to take a look at the Ember Router example by #ghempton, where it defines tab with Ember.Router.
You have 2 options:
1) each tabpage has its own controller, view and must also be defined in the router
<script type="text/x-handlebars" data-template-name="tabs">
<div>
<ul class="nav nav-tabs">
{{#view Bootstrap.TabItem item="info"}}
<a {{action gotoInfo}}>Info</a>
{{/view}}
{{#view Bootstrap.TabItem item="anamnese"}}
<a {{action gotoAnamnese}}>Anamnese</a>
{{/view}}
{{#view Bootstrap.TabItem item="medication"}}
<a {{action gotoMedication}}>Medication</a>
{{/view}}
</ul>
{{outlet}}
</div>
</script>
Bootstrap.TabItem = Ember.View.extend({
tagName: 'li',
classNameBindings: ['isActive:active'],
isActive: function() {
return this.get('item') === this.get('controller.selectedTab');
}.property('item', 'controller.selectedTab').cacheable()
});
2) all tabpages are in one large view, and tabpages will be hidden or shown
{{#view Ember.TabContainerView currentView="info"}}
<ul class="nav nav-tabs">
{{#view Bootstrap.TabView value="info"}}<a>Info</a>{{/view}}
{{#view Bootstrap.TabView value="anamnese"}}<a>Anamnese</a>{{/view}}
{{#view Bootstrap.TabView value="medication"}}<a>Medication</a>{{/view}}
</ul>
{{#view Ember.TabPaneView viewName="info"}}
{{view EEPD.InfoView}}
{{/view}}
{{#view Ember.TabPaneView viewName="anamnese"}}
{{view EEPD.AnamneseView}}
{{/view}}
{{#view Ember.TabPaneView viewName="medication"}}
{{view EEPD.MedicationView}}
{{/view}}
{{/view}}
Bootstrap.TabView = Ember.TabView.extend({
tagName: 'li',
classNameBindings: ['isActive:active'],
isActive: function() {
return this.get('value') === this.get('tabsContainer.currentView');
}.property('tabsContainer.currentView').cacheable()
});
There are two ways to implement a tab panel.
If you want your tabs to be bookmarkable, then you should implement them using Router:
Templates
<script type="text/x-handlebars" data-template-name="application">
<div class="tabpanel">
<div class="tabs">
<div {{action "goToFirstTab"}}>First tab</div>
<div {{action "goToSecondTab"}}>Second tab</div>
</div>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="firstTab">
First Tab content
</script>
<script type="text/x-handlebars" data-template-name="secondTab">
Second Tab content
</script>
Code:
var App = Ember.Application.create();
App.ApplicationController = Ember.Controller.extend();
App.ApplicationView = Ember.View.extend();
App.FirstTabView = Ember.View.extend({templateName: "firstTab"});
App.FirstTabController = Ember.Controller.extend();
App.SecondTabView = Ember.View.extend({templateName: "secondTab"});
App.SecondTabController = Ember.Controller.extend();
App.Router = Ember.Router.create({
root: Ember.Route.extend({
goToFirstTab: Ember.Route.transitionTo("firstTab"),
goToSecondTab: Ember.Route.transitionTo("secondTab"),
index: Ember.Route.extend({
route: "/",
redirectsTo: "firstTab"
}),
firstTab: Ember.Route.extend({
route: "/firstTab",
connectOutlets: function (router) {
router.get('applicationController').connectOutlet('firstTab');
}
}),
secondTab: Ember.Route.extend({
route: "/secondTab",
connectOutlets: function (router) {
router.get('applicationController').connectOutlet('secondTab');
}
})
})
});
App.initialize(App.Router);
The second way, without Router.
Templates (note that actions` targets are changed)
<script type="text/x-handlebars" data-template-name="application">
<div class="tabpanel">
<div class="tabs">
<div {{action "goToFirstTab" target="controller"}}>First tab</div>
<div {{action "goToSecondTab" target="controller"}}>Second tab</div>
</div>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="firstTab">
First Tab content
</script>
<script type="text/x-handlebars" data-template-name="secondTab">
Second Tab content
</script>
Code (pretty much the same, except that the code related to tabs is now moved to ApplicationController.
var App = Ember.Application.create();
App.ApplicationView = Ember.View.extend();
App.Router = Ember.Route.create();
App.FirstTabView = Ember.View.extend({templateName: "firstTab"});
App.FirstTabController = Ember.Controller.extend();
App.SecondTabView = Ember.View.extend({templateName: "secondTab"});
App.SecondTabController = Ember.Controller.extend();
App.ApplicationController = Ember.Controller.extend({
view: App.FirstTabView.create(),
goToFirstTab: function () {
this.connectOutlet("firstTab");
},
goToSecondTab: function () {
this.connectOutlet("secondTab");
}
});
App.initialize(App.Router);