derrida
asked on
angular 2 problem accessing json resutls
hi
so i have a for for edit, that the id is passed as a parameter. then onInit i have this to get the results from that id, and i do get it back from the database.
BUT when i try to access the values in the onInit i can but not in the template:
so i have an interface and i use it at the beginning of the class component:
location:Location;
then onInit i have this:
as you can see, here i can access the name value: () => console.log(this.location[ 0].name)
But in the template when i do the same:
{{location[0].name}}
in the console i get: EXCEPTION: TypeError: Cannot read property '0' of undefined
when i do {{location | json}} i get:
[ { "id": "1", "name": "sigliz coffee", "address": "hzel st 36,TA", "lat": "32.060143", "lng": "34.770557" } ]
what am i missing here? and how can i access the name for example?
best regards
so i have a for for edit, that the id is passed as a parameter. then onInit i have this to get the results from that id, and i do get it back from the database.
BUT when i try to access the values in the onInit i can but not in the template:
so i have an interface and i use it at the beginning of the class component:
location:Location;
then onInit i have this:
this._route.params
.map(params => params['id'])
.subscribe((id) => {
this.title = id ? "Edit Location" : "New Location";
if (!id) {
return;
}
//console.log(id);
this._locationService.getLocation(id)
.subscribe(
location => this.location = location,
error => alert(error),
() => console.log(this.location[0].name)
);
});
as you can see, here i can access the name value: () => console.log(this.location[
But in the template when i do the same:
{{location[0].name}}
in the console i get: EXCEPTION: TypeError: Cannot read property '0' of undefined
when i do {{location | json}} i get:
[ { "id": "1", "name": "sigliz coffee", "address": "hzel st 36,TA", "lat": "32.060143", "lng": "34.770557" } ]
what am i missing here? and how can i access the name for example?
best regards
ASKER
hey
it is on my local machine. but let me try to give you as much as possible.
i have a component with a form that will be used both to add or edit a location.
in my location service i have this method:
the php file query the database, and json_encode the results.
public location:Location; is an interface:
so in the template when i do: {{ location | json}}
i get: [ { "id": "1", "name": "sigliz coffee", "address": "hzel st 36,TA", "lat": "32.060143", "lng": "34.770557" } ]
but when i write: {{location.name}}
in the console i get that name is undifined. if i use the Elvis operator the error not shown in the console, but the name is not displying.
hope this is more info for you to help me.
it is on my local machine. but let me try to give you as much as possible.
i have a component with a form that will be used both to add or edit a location.
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, ROUTER_DIRECTIVES, CanDeactivate, Router } from '@angular/router';
import {FormBuilder,ControlGroup,Validators} from '@angular/common';
//import the service
import {LocationService} from '../location.service';
//import the interface
import {Location} from '../shared/location';
@Component({
moduleId: module.id,
selector: 'app-locationform',
templateUrl: 'locationform.component.html',
styleUrls: ['locationform.component.css'],
directives: [ROUTER_DIRECTIVES],
providers: [LocationService]
})
export class LocationformComponent implements OnInit {
title: string;
public location:Location;
form:ControlGroup;
constructor(
private _route: ActivatedRoute,
private _locationService: LocationService,
fb:FormBuilder
) {
this.form = fb.group({
name: ['', Validators.required],
address: ['', Validators.required],
lat: ['', Validators.required],
lng: ['', Validators.required],
});
var test = location;
//alert(this.location);
//console.log( this.location);
}
ngOnInit() {
//console.log(this._route.params['value']['id']);
this._route.params
.map(params => params['id'])
.subscribe((id) => {
this.title = id ? "Edit User" : "New User";
if (!id) {
return;
}
//console.log(id);
this._locationService.getLocation(id)
.subscribe(
location => this.location = location,
error => alert(error),
() => console.log( typeof this.location )
);
});
//console.log( typeof this.location);
}
}
in my location service i have this method:
getLocation(locationId){
let theparams = JSON.stringify({
action: 'getlocation',
id: locationId
});
let headers = new Headers();
headers.append('Content-Type','application/x-www-form-urlencoded;charset=utf-8');
return this._http.post(
'http://localhost:80/ang2router/public/dbactions.php',
theparams,
{headers: headers}
)
.map(res => res.json());
}
this is the method that is called from onInit before.the php file query the database, and json_encode the results.
public location:Location; is an interface:
export interface Location{
name: string;
address: string;
lat: number;
lng: number;
}
so in the template when i do: {{ location | json}}
i get: [ { "id": "1", "name": "sigliz coffee", "address": "hzel st 36,TA", "lat": "32.060143", "lng": "34.770557" } ]
but when i write: {{location.name}}
in the console i get that name is undifined. if i use the Elvis operator the error not shown in the console, but the name is not displying.
hope this is more info for you to help me.
ASKER
bizarre this: on the form tag i add: *ngFor="let loc of location" and them if i do {{loc.name}} it works. so we need to loop the returned data i guess
ASKER
jesus christ. if i do the *ngFor i can access the loc.name but if it is an add location form i get nothing and also no error messages in the log. so the my last comment doesn't really help
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
i get:
EXCEPTION: TypeError: Cannot read property '0' of undefined
EXCEPTION: TypeError: Cannot read property '0' of undefined
ASKER
Does the exception get reported before or after the AJAX call?
It does look like this is probably a synching issue
If you initialise location in your constructor to an array like this
Do you still get the exception?
If you initialise location in your constructor to an array like this
this.location = [{
name: 'No name'
}];
Do you still get the exception?
ASKER
i have written this in the constructor:
and before running it, i see:
Type '{ name: string; address: string; lat: string; lng: string; }[]' is not assignable to type 'Location'.
Property 'name' is missing in type '{ name: string; address: string; lat: string; lng: string; }[]'.
(property) LocationformComponent.loca tion: Location
this.location = [{
name: '',
address: '',
lat: '',
lng: ''
}];
because of the interface.and before running it, i see:
Type '{ name: string; address: string; lat: string; lng: string; }[]' is not assignable to type 'Location'.
Property 'name' is missing in type '{ name: string; address: string; lat: string; lng: string; }[]'.
(property) LocationformComponent.loca
when i do {{location | json}} i get:
[ { "id": "1", "name": "sigliz coffee", "address": "hzel st 36,TA", "lat": "32.060143", "lng": "34.770557" } ]
what am i missing here? and how can i access the name for example?
Allows you to convert a JavaScript object into JSON string
https://docs.angularjs.org/api/ng/filter/json
So why the index 0?
location must be a Javascript object. This location.name should give you the name.
ASKER
hi
i don't understand your point. i know that location.name should have given me the name, but it doesn't. that is why i asked the question.
i used the json pipe to see what i get.
i don't understand your point. i know that location.name should have given me the name, but it doesn't. that is why i asked the question.
i used the json pipe to see what i get.
I would like you to try :-
<div ng-repeat="location">
<div><span>The Name:</span></span>{{name} }</span></ div>
</div>
because IF location is an array, the repeat should produce at least one row.
And can I see the template?
<div ng-repeat="location">
<div><span>The Name:</span></span>{{name}
</div>
because IF location is an array, the repeat should produce at least one row.
And can I see the template?
ASKER
hi
you did noticed i am talking about angular 2 right?
the template at the moment is just a form and i am trying to populate it with the chosen location data. it will be an update form:
you did noticed i am talking about angular 2 right?
the template at the moment is just a form and i am trying to populate it with the chosen location data. it will be an update form:
<h1>{{title}}</h1>
<div class="row">
<div class="col-md-6 well">
<form [ngFormModel]="form" (ngSubmit)="save()"
>
<fieldset>
<legend>
Location - {{location | json}}
<br>
<!--test - {{location?.name}}-->
</legend>
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control">
<div class="alert alert-danger">
Name is required.
</div>
</div>
<div class="form-group">
<label>Address</label>
<input type="text" class="form-control">
<div class="alert alert-danger">
Please type a valid address.
</div>
</div>
<div class="form-group">
<label>Lat</label>
<input type="text" class="form-control">
</div>
<div class="form-group">
<label>Lng</label>
<input type="text" class="form-control">
</div>
</fieldset>
<button [disabled]="!form.valid" type="submit" class="btn btn-primary">
Save
</button>
</form>
</div>
</div>
ASKER
so in the constructor i log
console.log("From the constructor: " + this.location);
and i get undefined
while in the onInit
i get the returned object
console.log("From the constructor: " + this.location);
and i get undefined
while in the onInit
i get the returned object
ASKER
so just for test, i initialize the location variable like so:
and tried, and still couldn't access it in the template. so i commented the oninit part of calling the service and database, and then i do get access to my initialized values.
but it is bizzare since i log the this.location in the complete subscribe method and it is there, and as we know in the template when i use the json pipe it show it.
i'm lost
location:Location = {
name: 'some name',
address: 'some addredd',
lat: '45.74837',
lng: '32.98575'
};
and tried, and still couldn't access it in the template. so i commented the oninit part of calling the service and database, and then i do get access to my initialized values.
but it is bizzare since i log the this.location in the complete subscribe method and it is there, and as we know in the template when i use the json pipe it show it.
i'm lost
Can you post your code for LocationService and Location - I am intrigued - I want to setup a test project here to try and replicate the problem.
ASKER
hi sure.
this is my locationService code:
and the location interface:
this is my locationService code:
import { Injectable } from '@angular/core';
import {Http,Headers} from '@angular/http';
import { Observable } from 'rxjs/Observable';
//import the interface
import {Location} from './shared/location';
@Injectable()
export class LocationService {
constructor(private _http:Http) {}
getLocations():Observable<Location[]>{
let theparams = JSON.stringify({
action: 'getall'
});
let headers = new Headers();
headers.append('Content-Type','application/x-www-form-urlencoded;charset=utf-8');
return this._http.post(
'http://localhost:80/ang2router/public/dbactions.php',
theparams,
{headers: headers}
)
.map(res => res.json());
}
addLocation(){
}
deleteLocation(locationId){
let theparams = JSON.stringify({
action: 'delete',
id: locationId
});
let headers = new Headers();
headers.append('Content-Type','application/x-www-form-urlencoded;charset=utf-8');
return this._http.post(
'http://localhost:80/ang2router/public/dbactions.php',
theparams,
{headers: headers}
)
.map(res => res.json());
}
getLocation(locationId){
let theparams = JSON.stringify({
action: 'getlocation',
id: locationId
});
let headers = new Headers();
headers.append('Content-Type','application/x-www-form-urlencoded;charset=utf-8');
return this._http.post(
'http://localhost:80/ang2router/public/dbactions.php',
theparams,
{headers: headers}
)
.map(res => res.json());
}
searchLocation(){
}
}
and the location interface:
export interface Location{
name:string;
address:string;
lat:string;
lng:string;
}
ASKER
and maybe even the php side, even though this is just the basic queries and nothing more:
<?php
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Headers: X-Requested-With');
header('Content-Type: application/json');
$obj = json_decode(key($_POST));
//var_dump($obj);
// set up the connection variables
$db_name = 'locations';
$hostname = 'localhost';
$username = 'myusername';
$password = 'mypass';
// connect to the database
$dbh = new PDO("mysql:host=$hostname;dbname=$db_name", $username, $password);
switch ($obj->action) {
case 'getall':
// a query get all the records from the users table
$sql = 'SELECT * FROM markers';
// use prepared statements, even if not strictly required is good practice
$stmt = $dbh->prepare( $sql );
// execute the query
$stmt->execute();
// fetch the results into an array
$result = $stmt->fetchAll( PDO::FETCH_ASSOC );
echo json_encode($result);
break;
case 'add':
// a query get all the records from the users table
$sql = 'INSERT INTO markers ( name, address,lat, lng )
VALUES ( "' . $obj->name .'" , "'.$obj->address.'", "'.$obj->lat.'" , "'.$obj->lng.'" );';
// use prepared statements, even if not strictly required is good practice
$stmt = $dbh->prepare( $sql );
// execute the query
$check = $stmt->execute();
$last_id = $dbh->lastInsertId();
$sql2 = "SELECT * FROM markers WHERE id=$last_id ";
// use prepared statements, even if not strictly required is good practice
$stmt = $dbh->prepare( $sql2 );
// execute the query
$stmt->execute();
// fetch the results into an array
$result = $stmt->fetchAll( PDO::FETCH_ASSOC );
echo json_encode($result);
break;
case 'delete':
// a query get all the records from the users table
$sql = "DELETE FROM markers WHERE id=" . $obj->id;
// use prepared statements, even if not strictly required is good practice
$stmt = $dbh->prepare( $sql );
// execute the query
$check = $stmt->execute();
if ($check) {
$result = "Deleted successfully";
}else{
$result = "something went wrong";
}
echo json_encode($result);
break;
case 'getlocation':
// a query get the selected location
$sql = "SELECT * FROM markers WHERE id=" . $obj->id;
//var_dump($sql);
// use prepared statements, even if not strictly required is good practice
$stmt = $dbh->prepare( $sql );
// execute the query
$stmt->execute();
// fetch the results into an array
$result = $stmt->fetchAll( PDO::FETCH_ASSOC );
echo json_encode($result);
break;
default:
echo "this is default";
break;
}
Thanks - PHP i am just going to link the service to a text file with the JSON you posted above.
Nearly there - can you post your bootstrap script (main.ts)
ASKER
sure:
import { bootstrap } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppComponent, environment, AppRouterProvider } from './app/';
import {HTTP_PROVIDERS} from '@angular/http';
if (environment.production) {
enableProdMode();
}
bootstrap(AppComponent, [AppRouterProvider,HTTP_PROVIDERS]);
Trying to do this in the background so finding things as I go - where is your AppRouterProvider code - we can turf environment.
ASKER
in a file called: routes.ts:
notice the expoert
import {provideRouter, RouterConfig} from '@angular/router';
import {FirstpageComponent} from './firstpage/firstpage.component';
import {SecondpageComponent} from './secondpage/secondpage.component';
import {ThirdpageComponent} from './thirdpage/thirdpage.component';
import {FourthpageComponent} from './fourthpage/fourthpage.component';
import {Httptest2Component} from './httptest2/httptest2.component';
import {AnimationsComponent} from './animations/animations.component';
import {LocationformComponent} from './locationform/locationform.component';
export const appRoutes: RouterConfig = [
{path: 'first', component: FirstpageComponent},
{path: 'second', component: SecondpageComponent},
{path: 'third', component: ThirdpageComponent},
{path: 'fourth', component: FourthpageComponent},
{path: 'httptest2', component: Httptest2Component},
{path: 'animations', component: AnimationsComponent},
{path: 'locationform/new', component: LocationformComponent},
{path: 'locationform/:id', component: LocationformComponent},
{path: '', redirectTo: 'first'}
];
export const AppRouterProvider = provideRouter(appRoutes);
notice the expoert
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
the right direction and appreciate the time and efforts
You are welcome.
It looks like you are doing everything correctly but obviously something is missing as you are getting the error.
Have you tried initialising location - for example.
this.location = [{}]
It might be an async issue where the view is rendering before location has been set to at the time location[0] is not defined - although this should resolve
Are you saying that the view does not display the value or are you asking about the error in the console?
Very difficult to diagnose without seeing the full picture.