Angular 4 -> Push Objects to an Array - arrays

I'm having an issue with pushing a new object to an existing array.
What I am trying to do ->
I am trying to push a new card drawn into the existing array/object
app.component.ts
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
deck: any;
cards = [];
hand = 0;
cardCount: number;
constructor(private _data: DataService){
console.log("Data Service ready to query api");
};
newDeck(){
this._data.newDeck().subscribe(res => this.deck = res.json());
}
deal(cardCount){
this._data.deal(cardCount, this.deck.deck_id).subscribe(response => this.cards = response.json());
if(this.cards){
this.cards.push(this.cards);
}
}
app.component.html
<h1>New Game</h1>
<button (click)="newDeck()">Start</button>
<p>{{ deck.remaining }} cards left!</p>
<div>
<h2>Your Hand</h2>
<button (click)="deal(2)">Deal</button> <button (click)="deal(1)">Hit</button>
<img width="150" src="{{cards.cards[0].image}}">
<img width="150" src="{{cards.cards[1].image}}">
<img width="150" src="{{cards.cards[2].image}}">
<img width="150" src="{{cards.cards[3].image}}">
</div>
<!-- <div *ngFor="let card of cards">
<img src="{{card.cards.image}}" width="150px" style="padding: 50px; margin: 10px;">
</div> -->
Yes - My *ngFor is broken because it doesn't seem to believe the cards are stored in an array.
ERROR -> Error trying to diff '[object Object]'. Only arrays and iterables are allowed
Nevertheless, I attached a screenshot of what is happening. I can select the Deal button, but when I click Hit, the counter does only pull 1 card but it is not stored in the array. Instead, it acts as a new object and displays as card.cards[0].image instead of card.cards[2].image, since there are already 2 objects in the array after clicking the deal button.
Any ideas on how to push the new cards to into the cards array? Image
It may help to see how the cards are received when called ->
{
"remaining": 50,
"deck_id": "1omsivg9l9cu",
"success": true,
"cards": [
{
"image": "http://deckofcardsapi.com/static/img/KS.png",
"images": {
"svg": "http://deckofcardsapi.com/static/img/KS.svg",
"png": "http://deckofcardsapi.com/static/img/KS.png"
},
"suit": "SPADES",
"value": "KING",
"code": "KS"
},
{
"image": "http://deckofcardsapi.com/static/img/AH.png",
"images": {
"svg": "http://deckofcardsapi.com/static/img/AH.svg",
"png": "http://deckofcardsapi.com/static/img/AH.png"
},
"suit": "HEARTS",
"value": "ACE",
"code": "AH"
}
]
}

You can directly use the card.cards object in your ngFor
<span *ngFor="let item of data.cards">
<img src="{{item.image}}" width="150px" style="padding: 50px; margin: 10px;">
</span>

Related

V-for not working when building array from external JSON file

Javascript:
// List of Products
const productsJSON = 'json/products.json';
// Component - Product Select
app.component('product-select', {
data() {
return {
selected: '',
options: []
}
},
template: `
<p v-for="(option, index) in options">test</p>
<div class="ui fluid labeled multiple search selection dropdown">
<input type="hidden"
name="products"
v-model="selected"
#change="selectProducts">
<i class="dropdown icon"></i>
<div class="default text">Select Products</div>
<div class="menu">
<div v-for="(option, index) in options"
class="item"
v-bind:data-value="option.name">
{{ option.name }}
</div>
</div>
</div>
`,
methods: {
selectProducts(event) {
this.selected = event.target.value.split(',');
console.log(this.selected);
}
},
beforeMount() {
const jsonResults = [];
this.options = jsonResults;
$.getJSON(productsJSON, function (data) {
jsonResults.push(...data);
});
console.log(jsonResults);
console.log(this.options)
}
});
I'm simply trying to populate the options: [] array with the array of objects returned from the JSON file in the $.getJSON function. Here is what the JSON file looks like:
[
{
"name": "White Gummy",
"value": "White Gummy"
},
{
"name": "Red Gummy",
"value": "Red Gummy"
},
{
"name": "Blue Gummy",
"value": "Blue Gummy"
}
]
My v-for is returning absolutely nothing, and the results of my two console.log functions are as follows:
Does anyone have any idea on what I'm doing wrong or if there is a better way to populate my array with the external .json file?
#Luckyfella provided a solution, which can be found in the created() lifecycle hook below:
// Component - Product Select
app.component('product-select', {
data() {
return {
selected: '',
options: null
}
},
template: `
<div class="ui fluid labeled multiple search selection dropdown">
<input type="hidden"
name="products"
v-model="selected"
#change="selectProducts">
<i class="dropdown icon"></i>
<div class="default text">Select Products</div>
<div class="menu">
<div v-for="(option, index) in options"
class="item"
v-bind:data-value="option.name">
{{ option.name }}
</div>
</div>
</div>
`,
methods: {
selectProducts(event) {
this.selected = event.target.value.split(',');
console.log(this.selected);
}
},
created: function () {
fetch(productsJSON)
.then(r => r.json())
.then(options => {
this.options = options;
});
}
});

check with *ngIf, if there is an array or not (Angular 4)

I'm looping through a json file with *ngFor. While looping through the data, I want to check for every person, if it has no colors array. I do this with *ngIf.
JSON
[
{
"name": "Peter",
"colors": [
{
"color": "blue"
},
{
"color": "yellow"
}
]
},
{
"name": "Maria"
}
// has no colors array
]
HTML
<div *ngFor="let person of persons">
<div *ngIf=" what comes here?? ">
<p>{{person.name}} has no colors</p>
</div>
</div>
How can I check, if a person has no colors array?
Try this
<div *ngFor="let person of persons">
<div *ngIf="person.colors && person.colors.length">
With words, it gives
If the array exists and has at least one element in it
The opposite would be
<div *ngIf="!person.colors || !person.colors.length">
Which you can shorten with an Elvis operator
<div *ngIf="!person.colors?.length">
Very simply :
<div *ngIf="!person.colors">
<p>{{person.name}} has no colors</p>
</div>

How to pass JSON data to a modal in angular 2

I am trying to pop up a modal in angular 2 that will display a list of people. The source of the list is a JSON file. I think the data is not being properly bound to the table in the modal. I am new to angular 2 and am not sure what I am missing.
Service to read JSON file:
returns-json-array-service.ts
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs';
#Injectable()
export class ReturnsJsonArrayService {
constructor(private http: Http) {}
getPeople(): Observable<any> {
return this.http.request('./people.json')
.do( res => console.log('HTTP response:', res))
.map(res => res.json().payload)
.do(console.log);
//.map(res => res.json());
/*return this.http.get('./people.json')
.map((res:Response) => res.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));*/
}
}
SAmple json file: people.json
{
"id": "1",
"name": "David Martinez Ros",
"email": "info#davidmartinezros.com",
"age": "33"
},
{
"id": "2",
"name": "Paco Roberto Corto",
"email": "paco.roberto.corto#gmail.com",
"age": "51"
},
{
"id": "3",
"name": "Silvia Elegante i Latina",
"email": "silvia.elegante.latina#gmail.com",
"age": "30"
}
]
modal-component.ts
import {Component, Input} from '#angular/core';
import {NgbModal, NgbActiveModal} from '#ng-bootstrap/ng-bootstrap';
import { Observable } from 'rxjs';
import { ReturnsJsonArrayService } from './returns-json-array.service';
#Component({
selector: 'ngbd-modal-content',
providers: [ReturnsJsonArrayService],
template: `
<div class="modal-header">
<h4 class="modal-title">Hi there!</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
<div class="modal-body" *ngFor="let person of peopleData | async" >
<p>One fine body…</p>
<table border=1>
<tr>
<td>
<h3>Id: {{ person.id }}</h3>
</td>
<td>
<h3>name: {{ person.name }}</h3>
</td>
<td>
<h3>email: {{ person.email }}</h3>
</td>
<td>
<h3>age: {{ person.age }}</h3>
</td>
<td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="activeModal.close('Close click')">Submit</button>
</div>
`
})
export class NgbdModalContent {
#Input() name;
#Input() peopleData: Observable<Array<any>>;
constructor(public activeModal: NgbActiveModal,private peopleService: ReturnsJsonArrayService) {
this.peopleData = this.peopleService.getPeople();
console.log("AppComponent.data:" + this.peopleData);
}
}
#Component({
selector: 'ngbd-modal-component',
templateUrl: './modal-component.html'
})
export class NgbdModalComponent {
constructor(private modalService: NgbModal) {}
open() {
const modalRef = this.modalService.open(NgbdModalContent);
modalRef.componentInstance.name = 'Barb' ;
console.log("Peopledatra on open():" + modalRef.componentInstance.peopleData);
}
}
modal-component.html
<button class="btn btn-primary" (click)="open()">Assign</button>
this.peopleService.getPeople() returns an observable which is cold to activate it and make it hot you must add a subscribe this.peopleService.getPeople().subscribe() the subscribe will take a success method as the first argument like so:
this.peopleService.getPerople().subscribe(
(json) => {
// do something here with the json
}
)
Once the json is returned you can set it to a property within your components scope like so:
this.peopleService.getPerople().subscribe(
(json) => {
this.json = json;
}
)
That property will then be accessible with in the components template.

Displaying nested JSON data in AngularJS

I am building a cross platform app using Onsen UI, Monaca and AngularJS.
I have a screen where the user can select from various switches using Onsen UIs built in switches (Switch in List Item). Toggling a switch means that vehicle check needs to be performed, else it is assumed that all checks have passed.
I can display the Check Descriptions (checkitemdesc) as per the JSON below on the list item switches, but when I toggle any of the switches I want to be able to display their related "answers": [{...}] via a modal.
So toggling the "Engine oil level" switch, the user sees a modal with the related checks that can be performed on the "Engine oil level" e.g. Low, top up etc.
JSON example of the data
[{
"fleetcheckitemid": "1",
"checkitemdesc": "Engine oil level",
"answers": [{
"fleetcheckid": "1",
"checkvaluedesc": "Ok"
}, {
"fleetcheckid": "2",
"checkvaluedesc": "Low"
}, {
"fleetcheckid": "3",
"checkvaluedesc": "Top-Up Required"
}]
}, {
"fleetcheckitemid": "2",
"checkitemdesc": "Water level",
"answers": [{
"fleetcheckid": "1",
"checkvaluedesc": "Ok"
}, {
"fleetcheckid": "2",
"checkvaluedesc": "Low"
}, {
"fleetcheckid": "3",
"checkvaluedesc": "Top-Up Required"
}]
}]
My checksController.js used for getting JSON from $http API call which returns a JSON object.
$http.get("http://myfakedomain/api/getfleetchecks.php?fleetid=109").success(function(data)
{
$scope.checkItemDescriptions = data;
});
And my checks.html for displaying switches based on "checkitemdesc" in JSON.
<ul class="list">
<li class="list__item" ng-repeat="checkItemDescription in checkItemDescriptions">
{{checkItemDescription.checkitemdesc}}
<label class="switch switch--list-item">
<input type="checkbox"
class="switch__input"
checked >
<div class="switch__toggle"></div>
</label>
</li>
</ul>
Selecting any of the switches should fire the modal and populate it with the relevant "answers": [{...}] values
modal
<ons-modal var="modal">
<div class="alert-dialog-mask"></div>
<div class="alert-dialog alert-dialog--android">
<div class="alert-dialog-title alert-dialog-title--android">
<div style="text-align: center">Further Details</div>
</div>
<div class="alert-dialog-content alert-dialog-content--android">
<div style="text-align: center; padding-top: 10px; padding-bottom: 15px; padding-left: 10px; padding-right: 10px;">
<p>
Please give further details for<br>
<!-- Display the selected checkitemdesc here - NOT WORKING -->
<strong>{{checkItemDescription[i].checkvaluedesc[i]}}</strong>
</p>
</div>
<!-- Display sub-options for main sections - NOT WORKING-->
<div style="text-align: left; padding-top: 10px; padding-bottom: 15px; padding-left: 10px; padding-right: 10px;">
<!-- Display the selected subitems here - NOT WORKING -->
<label class="checkbox" ng-repeat="checkItemDescription in checkItemDescriptions[i].answers[i].checkvaluedesc">
<input type="checkbox">
<div class="checkbox__checkmark"></div>
<!-- Display the selected subitems here - NOT WORKING -->
{{checkItemDescription[i].answers[i].checkvaluedesc}}
</label>
</div>
</div>
</div>
</ons-modal>
I am able to display the main checks, but how do I do individual checks on each switch and then set the modal values based on that switch?
See this plunker: http://plnkr.co/edit/g952bdedUGuBhC5ez5Im?p=preview
What you do is:
Attach a selected: true/false to the checkitem level as well as the answers level.
Pass the selected row to the modal controller.
Use ng-repeat, using $filter to display the items.
The open modal function:
$scope.openModal = function(items) {
var selectedItems = [];
//get only the selected items
for(var i = 0; i < items.length; i++) {
if(items[i].selected === true) selectedItems.push(items[i]);
}
var modalInstance = $uibModal.open({
templateUrl: 'modalTemplate.html',
controller: MyModalCtrl,
backdrop: 'static',
keyboard: false,
resolve: { //pass selected items to the modal controller
fleetCheckItems: function() {return selectedItems;}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem; //user clicked okay
}, function () {
//user click cancel, figure out something to do with the promise
});
}

How to load image and text of that image paralelly into a div using angularjs

Actually,I'm able to load 3 images(open,new&save icons) into a div using angularjs.Now,I'm trying to place the related text of those images into the same div just below those 3 images.
Like,"open" text should be written just below "open" image.Simialrly,for the remaining images too.How can I achieve this?
Can anyone please help me out regarding this issue ...
My js code:
angular.module('Sample', []).controller('Home', function($scope) {
$scope.imageSources = [];
$scope.imageSources.push('images/open.png');
$scope.imageSources.push('images/new.jpg');
$scope.imageSources.push('images/save.png');
});
My html code:
<div style="margin-top: 15px;">
<img width=40 height=50 style="margin-left: 12px;"
ng-repeat="imageSource in imageSources track by $index"
ng-src="{{imageSource}}"> </img>
</div>
This will work but is not the right way to do it.
I leave the styling up to you.
View:
<div style="margin-top: 15px;" ng-repeat="imageSource in imageSources">
<img width=40 height=50 style="margin-left: 12px;" ng-src="{{imageSource}}" />
<br>
<span style="margin-left: 12px;">{{getFilenameFromPath(imageSource)}}</span>
</div>
Controller:
$scope.imageSources = [];
$scope.imageSources.push('images/open.png');
$scope.imageSources.push('images/new.jpg');
$scope.imageSources.push('images/save.png');
$scope.getFilenameFromPath = function(filename) {
return filename.split("/")[1].split(".")[0];
}
Here is a jsfiddle.
The right way as it has been mentioned in the contents, is to have a collection of object and each objects should have a name and a src property. In your case you should do:
$scope.imageSources = [];
$scope.imageSources.push({
name:"open",
src: "images/open.png"
});
$scope.imageSources.push({
name:"new",
src: "images/new.png"
});
$scope.imageSources.push({
name:"save",
src: "images/save.png"
});
So you will end up with this collection:
[
{
"name": "open",
"src": "images/open.png"
},
{
"name": "new",
"src": "images/new.png"
},
{
"name": "save",
"src": "images/save.png"
}
]
Here is an jsfiddle.

Resources