Solved

angular 2 problem accessing json resutls

Posted on 2016-07-31
29
93 Views
Last Modified: 2016-08-03
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:
    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)
            );
      });

Open in new window


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
0
Comment
Question by:derrida
  • 18
  • 9
  • 2
29 Comments
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41737046
Do you have a link that we can look at to see the error in context?

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.
0
 
LVL 1

Author Comment

by:derrida
ID: 41737076
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.
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);
      
      
  }

}

Open in new window


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

Open in new window

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

Open in new window


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.
0
 
LVL 1

Author Comment

by:derrida
ID: 41737094
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
0
 
LVL 1

Author Comment

by:derrida
ID: 41737206
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
0
 
LVL 51

Accepted Solution

by:
Julian Hansen earned 500 total points
ID: 41737209
"...we need to loop the returned data i guess "

You should be able to access the data as you have being - did you try the initialisation suggestion?

What do you get if you do this

{{ location[0] | json}}
0
 
LVL 1

Author Comment

by:derrida
ID: 41737213
i get:
 EXCEPTION: TypeError: Cannot read property '0' of undefined
0
 
LVL 1

Author Comment

by:derrida
ID: 41737218
and since i do in the sunscribe method: () => console.log( this.location  )

i get this added picture.the log
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41737248
Does the exception get reported before or after the AJAX call?
0
 
LVL 1

Author Comment

by:derrida
ID: 41737272
not sure actually. i attach the console image
console
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41737291
It does look like this is probably a synching issue

If you initialise location in your constructor to an array like this

this.location = [{
  name: 'No name'
}];

Open in new window


Do you still get the exception?
0
 
LVL 1

Author Comment

by:derrida
ID: 41737314
i have written this in the constructor:
    this.location = [{
      name: '',
      address: '',
      lat: '',
      lng: ''
    }];

Open in new window

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.location: Location
0
 
LVL 27

Expert Comment

by:BigRat
ID: 41737565

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.
0
 
LVL 1

Author Comment

by:derrida
ID: 41737818
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.
0
 
LVL 27

Expert Comment

by:BigRat
ID: 41737826
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?
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 1

Author Comment

by:derrida
ID: 41737869
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:

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

Open in new window

0
 
LVL 1

Author Comment

by:derrida
ID: 41738495
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
0
 
LVL 1

Author Comment

by:derrida
ID: 41738553
so just for test, i initialize the location variable like so:
  location:Location = {
      name: 'some name',
      address: 'some addredd',
      lat: '45.74837',
      lng: '32.98575'
    };

Open in new window


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
0
 
LVL 1

Author Comment

by:derrida
ID: 41738568
i attach pics of the console of the results from the php side, maybe you'll see something :
onetwo
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41738588
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.
0
 
LVL 1

Author Comment

by:derrida
ID: 41738593
hi sure.
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(){

  }

}

Open in new window


and the location interface:
export interface Location{
    name:string;
    address:string;
    lat:string;
    lng:string;
}

Open in new window

0
 
LVL 1

Author Comment

by:derrida
ID: 41738596
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;
}

Open in new window

0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41738756
Thanks - PHP i am just going to link the service to a text file with the JSON you posted above.
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41739104
Nearly there - can you post your bootstrap script (main.ts)
0
 
LVL 1

Author Comment

by:derrida
ID: 41739243
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]);

Open in new window

0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41739303
Trying to do this in the background so finding things as I go  - where is your AppRouterProvider code - we can turf environment.
0
 
LVL 1

Author Comment

by:derrida
ID: 41739315
in a file called: routes.ts:
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);

Open in new window


notice the expoert
0
 
LVL 1

Assisted Solution

by:derrida
derrida earned 0 total points
ID: 41740201
ok think i managed to understand.
two things bothered me: there are 2 subscriptions and accessing the returned data.

and i went back to the answers here:
julian you suggested : {{ location[0] | json}}
and i got and still get: EXCEPTION: TypeError: Cannot read property '0' of undefined

but i tried the [0] not in the templete but on the returned data, there it worked.

and also as i said it bothered me the double subscriptions, so i ended up doing this:
in the onInit:
    let theid = this._route.params['value']['id'];
    this.getTheLoc(theid);

Open in new window

and the getTheLoc method:
  getTheLoc(id){
        this.title = id ? "Edit Location" : "New Location";
        if (!id) {
          return;
        }else{
        //console.log(id);
        this.subscription = this._locationService.getLocation(id)
          .subscribe(
              location => this.location = location[0],
              error => alert(error),
              () => console.log(this.location)
            );
        }
      
  }

Open in new window


notice the  location[0]. if i put it here i get no errors and accessing location.name without issues.
0
 
LVL 1

Author Closing Comment

by:derrida
ID: 41740204
the right direction and appreciate the time and efforts
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41740255
You are welcome.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Introduction JSON is an acronym for JavaScript Object Notation.  It is a text-string data transport mechanism, capable of representing simple or complex data structures in a consistent and easy-to-read manner.  Similar in concept to XML, but more e…
This article demonstrates how to create a simple responsive confirmation dialog with Ok and Cancel buttons using HTML, CSS, jQuery and Promises
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now