Getting data from JSON ( AngularJS) - json

I've got the whole questions that I have in my JSON file, but I need only one until the user will click the right answer and go to the next one
HTML template:
<div ng-controller="quizController">
<ul>
<li ng-repeat="q in allData">
<h1 id="question">{{q.question}}</h1>
</li>
</ul>
<div class="answers">
<a class="btn btn-primary"><p>New York</p></a>
<a class="btn btn-warning"><p>Miami</p></a>
<a class="btn btn-success"><p>Washington</p></a>
<a class="btn btn-danger"><p>LA</p></a>
</div>
JS:
app.controller("quizController", function($scope, $http){
$http.get("questions.json")
.then(function(response){
$scope.allData = response.data;
});
});
JSON file:
[
{
"question": "Which is the largest country in the world by population?",
"options": ["India", "USA", "China", "Russia"],
"answer": 2
},
{
"question": "When did the second world war end?",
"options": ["1945", "1939", "1944", "1942"],
"answer": 0
},
{
"question": "Which was the first country to issue paper currency?",
"options": ["USA", "France", "Italy", "China"],
"answer": 3
},
{
"question": "Which city hosted the 1996 Summer Olympics?",
"options": ["Atlanta", "Sydney", "Athens", "Beijing"],
"answer": 0
}
]

You should not use ng-repeat then, since this will just loop through your questions and show them all at once in the UI.
Instead, store your questions array in another variable and then bind your UI to a specific index of that variable.
app.controller("quizController", function($scope, $http){
$scope.allData = [];
//Initially set to first element (question), then you will need to increment in further logic elsewhere probably on a button click handler if the answer is correct
$scope.currentQuestion = $scope.allData[0];
$http.get("questions.json")
.then(function(response){
$scope.allData = response.data;
});
});

This is similar to mindparses approach but goes a little deeper. You can navigate back and forth. It's not full proof but should help you on your way.
HTML
<div ng-app="app" ng-controller="quizController">
<div ng-app="app" ng-controller="quizController">
<p>
<h1 id="question">{{currentQ.question}}</h1>
<div class="answers">
<ul ng-repeat="option in currentQ.options">
<li>{{option}}</li>
</ul>
</div>
</p>
<button ng-click="move(-1)">Previous</button>
<button ng-click="move(1)">Next</button>
</div>
</div>
JS/CONTROLLER
var app = angular.module('app', []);
app.controller("quizController", function ($scope) {
$scope.move = function (direction) {
// you're gonna need an IF block here to stop it from going out of range.
var position = $scope.allData.indexOf($scope.currentQ);
$scope.currentQ = $scope.allData[position + direction];
}
$http.get("questions.json").then(function(response){
$scope.allData = response.data;
$scope.currentQ = $scope.allData[0];
});
});
JSFIDDLE

Related

Refresh cdkDropListData after dialog closes and element is removed from array

I have the angular drag and drop list set up like this:
<div class="row col-12" *ngFor="let level of team_heirarchy; let i=index;">
<div class="col-3">
<p>{{level.name}}</p>
</div>
<div class="col-9">
<div cdkDropList id="{{level.key}}" [cdkDropListData]="level.value"
[cdkDropListConnectedTo]="heirarchy_levels" class="example-list" [cdkDropListDisabled]="level.disabled" (cdkDropListDropped)="drop($event)">
<div class="example-box" *ngFor="let item of level.value; let j=index;" cdkDrag>{{item}}
<button *ngIf="!level.disabled" mat-icon-button color="warn" (click)="deleteHeirarchyItem(i, j)"><mat-icon>cancel</mat-icon>
</button></div>
</div>
</div>
</div>
And the TS File:
team_heirarchy = [
{
"name": "Level 1(ROOT)",
"key": "level1",
"value": ["Administration"],
"disabled": true
},
{
"name": "Level 2",
"key": "level2",
"value": ["Lead HR", "Lead Manager"],
"disabled": false
}
]
deleteHeirarchyItem(i: number, j: number){
this.dialog.open(ConfirmDialogComponent, {
height: "auto",
width: "500px",
data:{
message: "Are you sure you want to delete this position.",
}
}).afterClosed().subscribe(result => {
if(result){
this.team_heirarchy[i].value.splice(j, 1)
}
})
}
The problem is, if I place this line
this.team_heirarchy[i].value.splice(j, 1)
outside the mat-dialog, the ui is updated instantly and the element is removed from the drop list.
But if I continue this way and wait till the user confirms and dialog closes with a positive result, the element is removed from the array but on the ui the element is still there until I try to drag an element.
Any help?

Create full menu based on Json file

I have a fully functional menu (static), as im going to post, i want to replicate it based on what i get from a json file, i mean, create menu based on json file.
heres what i want as a menu:
html:
<div class="menu-container" >
<div class="menu">
<nav class="navbar-toggleable-md">
<div id="toggle" class="navbar-toggler"><a></a>
</div>
</nav>
<ul id="my_styles" class="rowcenter" >
<li>
<a role="button" class="button button4 menu-button" ><i role="button" class="icon-ambientais fs1 icon menu-button"></i><span class="button-text rowcenter menu-button">menu1</span></a>
<ul class="menu-list">
<li>
<i style="color: white" class="icon-ambientais fs1"></i>submenu
<ul>
<li>{{ 'submenu</li>
<li>submenu</li>
<li>{{ 'Imagens' | translate }}</li>
</ul>
</li>
<li>
<i style="color: white" class="icon-gestao-ambient fs1"></i>submenu3
<ul>
<li>submenu2</li>
<li>submenu2</li>
<li>submenu2</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
i have javascript to make it work.
I was searching for some help, because i cant figute it out..
i found that example, but i can't make it look like what i need.
https://www.codeproject.com/Articles/311758/Building-Menu-from-JSON
(passing the json obj to json file)
but i can't make it work like the menu i have.. if i change, for example, <ul> to <ul class="bla"> on this one, it breaks.
then i found that: Creating a Menu from JSON
but no success..
heres my trying code:
on html i just call
my typescript file:
.ts
ngOnInit() {
this._menu.getMenu()
.subscribe( res => {
let data = res;
console.log(data);
var getMenuItem = function (itemData) {
var item = $("<li>")
.append(
$("<a>", {
href: itemData.link,
html: itemData.name
}));
if (itemData.sub) {
var subList = $("<ul>");
$.each(itemData.sub, function () {
subList.append(getMenuItem(this));
});
item.append(subList);
}
return item;
};
var $menu = $("#menu");
$.each(data.menu, function () {
$menu.append(
getMenuItem(this)
);
});
$menu.menu();
});
}
had somebody done something like this before?
if someofyou have a working example with one menu item and submenu, even without img, i would appreciate it.
thank you.
Ok i got the solution!
Having al lthe css and html done, i've just got the JSON file to array that way:
this._menu.getMenu()
.subscribe( res => {
let data = res;
console.log(data);
this.arr = data;
this.arr = (<any>Object).values(data);
});
Then, on html i just picked the menus and sub menus names / links / icons, and ngfor them into the already made tags:
<li *ngFor="let item of arr[0]; let i = index;">
<a role="button" class="button button4 menu-button" ><i role="button" class={{item.class}}></i><span class="button-text rowcenter menu-button">{{item.name}}</span></a>
<ul class="menu-list" *ngIf=item.sub>
<li *ngFor="let sub of item.sub; let j = index;">
<i style="color: white" class={{item.sub[j].class}}></i>{{item.sub[j].name}}
<ul *ngFor="let smn of sub.submenu; let x = index;">
<li>{{smn.name}}</li>
</ul>
</li>
</ul>
</li>
heres the JSON i've used:
{
"menu": [
{
"name": "Menu Name",
"link": "link",
"class": "icon-ambientais fs1 icon menu-button",
"sub": [{
"name": "SubMenuTitle1",
"link": "link",
"class": "icon-ambientais fs1",
"submenu":[{
"name": "SubMenu1",
"routerlink": "/link/Qld"
},{
"name": "SubMenu2",
"routerlink": "/link/eQld"
},{
"name": "SubMenu3",
"routerlink": "/link/aQld"
}
]
},
{
"name": "SubMenuTitle2",
"link": "link",
"class": "icon-gestao-ambient fs1",
"submenu":[{
"name": "SubMenu1",
"routerlink": "/link2/oQld"
},{
"name": "SubMenu2",
"routerlink": "/doc/eQld"
}
]
}
]
}
}
Hope that helps somebody on the futurue

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>');
});

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);