display json that is in a array - html

looking to display title values from json file. but in the HTML it can only dig down to an array and displays object: object. I'm looking to find the title which is located under sections.0.foreground.title. do I need to add something to my home.ts or can it all be in the HTML? thanks
cannot read property'0" of undefined
new html error
Home.html
<ion-header>
<ion-navbar>
<ion-title>Home</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<form [formGroup]="storymap" (ngSubmit)="logForm()">
<ion-item>
<ion-label color="primary">URL</ion-label>
<ion-input type="text" placeholder="Storymap URL" formControlName="storymapurl" [(ngModel)]="inputName"></ion-input>
</ion-item>
<ion-item> *ngFor="let item of result.values.sections">
<button ion-button (click) = "getData()">Get Data</button>
<ion-row>Title:{{item.foreground.title}}</ion-row>
</ion-item>
<ion-item>
<ion-label>storymap</ion-label>
<ion-input type="text" formControlName="title"></ion-input>
</ion-item>
<ion-item>
<ion-label>Description</ion-label>
<ion-textarea formControlName="description"></ion-textarea>
</ion-item>
<button ion-button type="submit" [disabled]="!storymap.valid">Submit</button>
</form>
home.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import {Validators, FormBuilder, FormGroup } from '#angular/forms';
import {HttpClient,HttpHeaders} from '#angular/common/http'
import { Observable } from 'rxjs/Observable';
import $ from 'jquery'
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
private storymap : FormGroup;
result:any= [];
data: Observable<any>;
public inputName: string;
constructor(public navCtrl: NavController, public http:HttpClient, private formBuilder: FormBuilder) {
this.storymap = this.formBuilder.group({
storymapurl: [''],
title: ['', Validators.required],
description: [''],
});
}
getData(){
this.inputName;
console.log('here', this.inputName)
this.data = this.http.get(this.inputName);
this.data.subscribe(data => {
this.result = data;
// console.log(data)
this.title = data.sections[0].foreground.title
console.log(this.title)
});
}
logForm(){
console.log(this.storymap.value)
}
}

So after our convo I think I understood your use case:
* user clicks Button getData()
* users sees data's title for the first item in sections?
Then you need to do:
<form [formGroup]="storymap" (ngSubmit)="logForm()">
<ion-item>
<ion-label color="primary">URL</ion-label>
<ion-input type="text" placeholder="Storymap URL" formControlName="storymapurl" [(ngModel)]="inputName"></ion-input>
</ion-item>
<ion-item>
<button ion-button (click) = "getData()">Get Data</button>
<ion-row>Title:{{title}}</ion-row>
</ion-item>
<ion-item>
<ion-label>storymap</ion-label>
<ion-input type="text" formControlName="title"></ion-input>
</ion-item>
<ion-item>
<ion-label>Description</ion-label>
<ion-textarea formControlName="description"></ion-textarea>
</ion-item>
<button ion-button type="submit" [disabled]="!storymap.valid">Submit</button>
</form>
And in your ts file:
export class HomePage {
private storymap : FormGroup;
private title: string;
private inputName: string = "https://www.arcgis.com/sharing/rest/content/items/b9ec967ce39a49cd8de6fd24aa14d477/data?f=json"
private result: any;
constructor(public navCtrl: NavController, public http:HttpClient, private formBuilder: FormBuilder) {
this.storymap = this.formBuilder.group({
storymapurl: [''],
title: ['', Validators.required],
description: [''],
});
}
getData(){
this.http.get(this.inputName).subscribe(data => {
this.result = data;
this.title = this.result.values.sections[0].foreground.title;
console.log(this.result.values.sections[0].foreground.title)
});
}
If this still produces error - please console log what you get in response above.
Here is working blitz:
https://stackblitz.com/edit/ionic-yuvxgm

Related

I use reactive form in my ionic app it give error

page.html
<form [formGroup]="directionForm">
<ion-item>
<ion-label position="floating">Source</ion-label>
<ion-input [(ngModel)]="source" formControlName="source"></ion-input>
</ion-item>
<ion-item>
<ion-label position="floating">Destination</ion-label>
<ion-input [(ngModel)]="destination" formControlName="destination"></ion-input>
</ion-item>
<ion-button expand="full" type="submit"
(click)="calculateAndDisplayRoute(directionForm.value)"
[disabled]="directionForm.invalid">Get Direction</ion-button>
</form>
page.ts
import {FormBuilder,Validators,FormGroup } from "#angular/forms";
constructor(
private fb: FormBuilder,
) {
this.createDirectionForm(); }
createDirectionForm() {
this.directionForm = this.fb.group({
'source': ['', Validators.required],
'destination': ['', Validators.required]
});
}
app.module.ts
import { FormsModule,ReactiveFormsModule } from '#angular/forms';
imports: [
FormsModule,
ReactiveFormsModule,]
I used this form many times in my app. but now it gives an error. I don't know where am going wrong please help me to rectify this code thank you for your help

Show specific data for the clicked element using popover

when I retrieve data from a json file, in the *ngFor displays all the values in the popover, but I need a specific popover to display based only on the data for selected/clicked weapon. Here is my code any help would be greatly appreciated. Thank you again for your help
Home
import { Component } from '#angular/core';
import { NavController, ViewController, PopoverController, Events} from 'ionic-angular';
import { RestProvider } from './../../providers/rest/rest';
import { PopupPage } from './../../pages/popup/popup';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
weapons: any;
errorMessage: string;
constructor(public navCtrl: NavController, public rest: RestProvider,
public popoverCtrl: PopoverController) {
}
ionViewDidLoad() {
this.getweapons();
}
getweapons() {
this.rest.getweapons()
.subscribe(
weapons => this.weapons = weapons,
error => this.errorMessage = <any>error);
}
presentPopover(myEvent)
{
let popover = this.popoverCtrl.create(PopupPage);
popover.present({
ev: myEvent
});
}
}
home.html
<ion-content>
<ion-searchbar [(ngModel)]="terms"></ion-searchbar>
<ion-item>
</ion-item>
<ion-list>
<button ion-item (click)="presentPopover($event)">
<ion-item *ngFor="let c of weapons?.weapon_category?.weapons | search : terms">
<h2>{{c.name}}</h2>
</ion-item>
</button>
</ion-list>
</ion-content>
popup.ts
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams, ViewController, Events} from 'ionic-angular';
import { RestProvider } from './../../providers/rest/rest';
import { HomePage } from './../../pages/home/home';
/**
* Generated class for the PopupPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-popup',
templateUrl: 'popup.html',
})
export class PopupPage {
rangeSettings = 20;
weapons: any;
errorMessage: string;
constructor(public navCtrl: NavController, public navParams: NavParams, public viewCtrl: ViewController, public rest: RestProvider) {
alert('inside the popup');
}
close() {
this.viewCtrl.dismiss();
}
getweapons() {
this.rest.getweapons()
.subscribe(
weapons => this.weapons = weapons,
error => this.errorMessage = <any>error);
}
ionViewDidLoad() {
this.getweapons();
}
}
popup.html
<ion-header>
<ion-navbar>
<ion-title>popup</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item *ngFor="let c of weapons?.weapon_category?.weapons">
<h2>{{c.damage.base}}</h2>
<h2>{{c.damage.chest0}}</h2>
<h2>{{c.damage.chest1}}</h2>
<h2>{{c.damage.chest2}}</h2>
<h2>{{c.damage.chest3}}</h2>
<h2>{{c.damage.head1}}</h2>
<h2>{{c.damage.head2}}</h2>
<h2>{{c.damage.head3}}</h2>
</ion-item>
<ion-item>
<ion-range min="0" max="80" [(ngModel)]="rangeSettings" color="danger" pin="true" snaps="true" disabled=true></ion-range>
</ion-item>
</ion-list>
</ion-content>
Popover doesn't need to hit the REST call again. You can pass the chosen weapon to the popover as a parameter.
Change your function to accept a weapon (make sure you change the code in the HTML too)
presentPopover(myEvent, weapon)
And send it to the popover controller this way:
this.popoverCtrl.create(PopupPage, weapon);
Now in your popup.ts, decleare a weapon object in your class,
weapon : any;
and grab the weapon from the navParams in your constructor
this.weapon = this.navParams.data;
Change your <ion-item> in popup.html to display the selected one.
<ion-item>
{{weapon.damage.base}}
...
</ion-item>

Check for password match before form submission with Angular 2

I'm working on a user registration page, where I'm able to validate the forms to make sure it's filled before sending it to the database.
Now what I want to achieve is to make sure, that the user's password matches before the button is being made active to send.
JS:
constructor(public navCtrl: NavController,
public http: Http,
public loadingCtrl: LoadingController,
public alertCtrl: AlertController,
public toastCtrl: ToastController,
public formBuilder: FormBuilder) {
this.createUsernameForm = this.formBuilder.group({
username: ['', Validators.required],
password: ['', Validators.compose([Validators.required, Validators.minLength(6)])],
retypePassword:['',Validators.required]
});
HTML:
<form [formGroup]="createUsernameForm">
<ion-item>
<ion-label floating>Username</ion-label>
<ion-input type="text" formControlName="username" [(ngModel)]="username" (ngModelChange)="username = $event.toLocaleLowerCase()"></ion-input>
</ion-item>
<ion-item>
<ion-label floating>Password</ion-label>
<ion-input type="password" formControlName="password" [(ngModel)]="password"></ion-input>
</ion-item>
<ion-item>
<ion-label floating>Retype Password</ion-label>
<ion-input type="password" formControlName="retypePassword" [(ngModel)]="retypePassword"></ion-input>
</ion-item>
<div>Passwords do not match!</div>
<p>
<button icon-left ion-button large full (click)="createUsername()" [disabled]="!createUsernameForm.valid">
<ion-icon name="arrow-dropright"></ion-icon>
Sign In
</button>
</p>
</form>
You need to create a custom validator, to compare both Controls, and apply this validator in your formGroup.
Example:
static EqualValidator(c1: AbstractControl, c2: AbstractControl): ValidatorFn {
return () => {
return c1 && c2 && c1.value === c2.value ? null : {notMatch: true};
};
}
use (input)=validatePassword() on the <ion-input> of retype password then do your validation logic inside validatePassword() and set the flag to true to enable the button

Ionic 2 will not let me loop over an object of objects using *ngFor

I am developing an app where users can search for classified ads.
However, I am unable to display the search results.
Here is my search_results.ts:
import {Component} from '#angular/core';
import {NavController, NavParams} from 'ionic-angular';
import {Http} from '#angular/http';
import 'rxjs/add/operator/map';
#Component({
selector: 'page-page1',
templateUrl: 'search_results.html' })
export class SearchResults {
public term: any;
public ads: any;
public tmp: any;
constructor(public navCtrl: NavController, public params: NavParams, public http: Http) {
this.term = this.params.get('term');
this.ads = [];
this.tmp = [];
console.log("this.term", this.term);
this.http.get('http://www.truckers.host/app/search-ads.php')
.map(res => res.json()).subscribe(data => {
console.log("this is returned from http.get", data);
});
}
ngOnInit() {
// Let's navigate from TabsPage to Page1
console.log(this.params);
} }
Now, in my search_results.html to display the search results, I am not getting anything to print.
Here is that code:
<ion-header>
<ion-navbar>
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>
<img src="assets/images/trucker-to-trucker-logo.png" />
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding class="card-background-page">
<ion-card>
<ion-card-header>
Search Results
</ion-card-header>
<ion-card-content>
Searching for: <b>{{ term }}</b>
</ion-card-content>
</ion-card>
<ion-card>
<ion-list>
<ion-item *ngFor="let ad of ads">
{{ ad.ad_id }}
</ion-item>
</ion-list>
</ion-card>
</ion-content>
Nothing is returned, or iterated over.
When I console.log(data), I get an Object of Objects, and Ionic does not want to loop them.
Please let me know what other information I should include to help.
*ngFor only supports for Array and not Json Object.
You should consider using a custom Pipe to convert Object to Array.
Documentation about Pipe.
#Pipe({name: 'toArray'})
export class ToArrayPipe implements PipeTransform {
transform(inputObj: any, arg: any) {
if (!inputObj) { return [] }
let arr = [];
for(let key in inputObj) {
// Option1 (only value without the json object's key)
// this way will lose the key of Json Object
//arr.push(inputObj[key]);
// OPtion2 (both the key and value)
let obj = {};
obj[key] = inputObj[key];
arr.push(obj);
}
return arr;
}
}
Then add it to declarations of NgModule, and use it in your temple this way:
<ion-item *ngFor="let ad of ads | ToArray">
...
</ion-item>

User data not showing on Html page in Ionic 2 and Firebase 3

I am using a project to get some user data from Firebase. I want to put that data into a "Profile page". Everything works except for one problem. The data doesn't show on the html page until I click on an item in the page, like to edit some data for example. The data will also show if I click back, then reenter the page. So it's like the data loads the blank template, but never updates it once the data from Facebook is received. Any suggestions? Here is some of the code from the page.
profile.html
<ion-header>
<ion-navbar color="primary">
<ion-title>Profile</ion-title>
<ion-buttons end>
<button ion-button item-left icon-right (click)="logOut()">
<ion-icon name=""></ion-icon>
Logout
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-list>
<ion-list-header>
Personal Information
</ion-list-header>
<ion-item (click)="updateName()">
<ion-grid>
<ion-row>
<ion-col width-50>
Name
</ion-col>
<ion-col *ngIf="userProfile?.firstName || userProfile?.lastName">
{{userProfile?.firstName}} {{userProfile?.lastName}}
</ion-col>
<ion-col class="placeholder-profile" *ngIf="!userProfile?.firstName">
<span>
Tap here to edit.
</span>
</ion-col>
</ion-row>
</ion-grid>
</ion-item>
<ion-item>
<ion-label class="dob-label">Date of Birth</ion-label>
<ion-datetime displayFormat="MMM D, YYYY" pickerFormat="D MMM YYYY"
[(ngModel)]="birthDate" (ionChange)="updateDOB(birthDate)"></ion-datetime>
</ion-item>
<ion-item (click)="updateEmail()">
<ion-grid>
<ion-row>
<ion-col width-50>
Email
</ion-col>
<ion-col width-50 *ngIf="userProfile?.email">
{{userProfile?.email}}
</ion-col>
<ion-col class="placeholder-profile" *ngIf="!userProfile?.email">
<span>
Tap here to edit.
</span>
</ion-col>
</ion-row>
</ion-grid>
</ion-item>
<ion-item (click)="updatePassword()">
<ion-grid>
<ion-row>
<ion-col width-50>
Password
</ion-col>
<ion-col class="placeholder-profile">
<span>
Tap here to edit.
</span>
</ion-col>
</ion-row>
</ion-grid>
</ion-item>
</ion-list>
</ion-content>
Here is the code from the profile.ts page
import { NavController, AlertController } from 'ionic-angular';
import { Component } from '#angular/core';
import { ProfileData } from '../../providers/profile-data';
import { AuthData } from '../../providers/auth-data';
import { LoginPage } from '../login/login';
#Component({
selector: 'page-profile',
templateUrl: 'profile.html',
})
export class ProfilePage {
public userProfile: any;
public birthDate: string;
zone: NgZone;
constructor(public navCtrl: NavController, public profileData: ProfileData,
public authData: AuthData, public alertCtrl: AlertController) {
}
ionViewDidEnter(){
this.profileData.getUserProfile().on('value', (data) => {
this.userProfile = data.val();
this.birthDate = this.userProfile.birthDate;
});
}
I also tried wrapping it in an NgZone object as suggested by others, which looks like this:
import { NavController, AlertController } from 'ionic-angular';
import { Component } from '#angular/core';
import { ProfileData } from '../../providers/profile-data';
import { AuthData } from '../../providers/auth-data';
import { LoginPage } from '../login/login';
import { NgZone } from '#angular/core';
#Component({
selector: 'page-profile',
templateUrl: 'profile.html',
})
export class ProfilePage {
public userProfile: any;
public birthDate: string;
zone: NgZone;
constructor(public navCtrl: NavController, public profileData: ProfileData,
public authData: AuthData, public alertCtrl: AlertController) {
this.zone = new NgZone({});
this.zone.run(() => {
//Your promise code
this.profileData.getUserProfile().on('value', (data) => {
this.userProfile = data.val();
this.birthDate = this.userProfile.birthDate;
});
});
}
None of this seems to work. The data is there, it just doesn't show until I click on an item/UI object, then it populates correctly. Help!
You have to do it like below.Hope code is self-explanatory.If you have any question, please comment below.
How to install Angularfire2?
ProfileData.ts
import { AngularFire, FirebaseListObservable, FirebaseObjectObservable } from 'angularfire2';
#Injectable()
export class ProfileData {
constructor(public af: AngularFire) {}
getUserProfile(data: string): FirebaseObjectObservable<any> {
return this.af.database.object(`path-to-your-firebase-object`);
}
}
YourComponent.ts
public profile: any;
constructor(public profileData: ProfileData) {
this.profileData.getUserProfile(your-user-id).subscribe(profileSnap => {
this.profile= profileSnap ;
});
}