Why the provider return 'null' value for web service json?


#1

Friends,
I am using web service and forms for a number of situations in my project. But now when I try to use same strategy the data is not provided by the provider function. It gives ‘null’ value always. But I can see the value in chrome web console.
My provider function is

  getYearMaster() 
  {
    var obj = {wsname: 'YearMaster' };
    var myData = JSON.stringify(obj);
    if(this.data)
    {
      return Promise.resolve(this.data);
    } else {
      return new Promise 
      (
        resolve => 
                    {
                      this.http.post('http://apps.windows.gov.in/mobservice/index.php/xxx/',myData,{ headers: new HttpHeaders()
                      , responseType: 'json'})
                      .map(res => res)
                      .subscribe
                                 (res => {
                                    resolve(res);
                                   },
                                   err => {console.log("oops some error in Project Financial year selection");}
                                 );
                    }
      );
    }


  }


the calling controller is

getYearMaster() 
  {
    let loader = this.loadingController.create({
      content: "Loading Financial Year ... "
    });  
    loader.present();
    if(this.global1.getnetwork())
    {
      this.connectivityFlag = true;
      this.projectplanprovider.getYearMaster()
      .then(data => {
        this.searchFlag = true;
        this.result = data;
        alert("data in fun is:"+data); // data in fun is 'null'
        this.year = data;
        loader.dismiss();
      }, error => {
        alert("error recieved : " + error ); //it will not happen any time 
         loader.dismiss();
     });
    } else {
      this.presentAlert();
    } 
  }

What may be the problem ? I could not find any error . Please advise

Thanks

Anes


#2

@anespa Try to put some logs to see what is happening in the provider:

public getYearMaster() {
	const obj = {wsname: 'YearMaster' };
	const myData = JSON.stringify(obj);

	if (this.data) {
		console.log('already has the data', this.data);
		return Promise.resolve(this.data);
	} else {
		return new Promise(resolve => {
			console.log('will call the web service');
			
			const url = 'http://apps.windows.gov.in/mobservice/index.php/xxx/';
			this.http.post(url, myData, { headers: new HttpHeaders(), responseType: 'json'}).map(res => {
				console.log('res1', res);				
				return res; // is this map needed, when it is returning the same value?
			}).subscribe(
				res => {
					console.log('res2', res);	
					resolve(res);
				}, 
				err => { 
					console.log('oops some error in Project Financial year selection'); 
				}
			);
		});
	}
}

See if the logs are correct:

will call the web service
res1 [value]
res2 [value]

Or if this.data is defined:

already has the data [value]

Check if the value is correct, and where it is returned.


#3

Hey man I just wanted to say that you are leveraging promise and an observable inside of it…I am not sure what makes your use case (to retrieve data from a service) so unique that you are using this pattern?

Highly advise you to use simple approaches:

  • create methods that return observables for your API calls
  • call to subscribe to those methods from your components

Try to use the patterns advised at angular.io as much as you can to avid these snowflakes.


#4

Dear @morphist, @lucasbasquerotto and others,

Actually my problem is the code works and it go fast without getting a value from server . I need a solution which work like await/async. Please advise in current code how it can implement ?

Waiting fast reply

Anes


#5

Dear Lucas,
I got console output as

res1 null
res2 null

Any solution?


#6

Hey have you maybe looked in into .toPromise()?

https://www.learnrxjs.io/operators/utility/topromise.html

might help you get this code a little bit cleaner.

import { toPromise } from 'rxjs/operators';

public getYearMaster() {
	const obj = {wsname: 'YearMaster' };
	const myData = JSON.stringify(obj);

	if (this.data) {
		console.log('already has the data', this.data);
		return Promise.resolve(this.data);
	} else {
		console.log('will call the web service');
			
		const url = 'http://apps.windows.gov.in/mobservice/index.php/xxx/';
		return this.http.post(url, myData, { headers: new HttpHeaders(), responseType: 'json'}).toPromise();
	}
}

also what I would advise is to use an interface to define the data that is being fetched in the http request and returned in the promise.


#7

Dear @kgaspar,

When I try to implement your code in provider i got error as shown in Editor view given below

Please advise what I change

Anes


#8

Hey Anes,

try adding this import to your code

import 'rxjs/add/operator/toPromise';


#9

Watchout for CORS also.


#10

How it can @uddyvky ??


#11

CORS doesn’t allow the value to pass resulting in null value.
Check your backend.
I’m not too sure about this but it may be because of this.


#12

But in console I get the json value of the result. Problem is in our provider return.


#13

This is a typical error found when we work with Angular and Ionic, the problem appears because when your app loaded in a browser on your app loads all the content from an origin that comes from your local address http://localhost:8100, then when you want to make any AJAX request sent out to another host than localhost:8100 the request is called from an any point different from the origin its require a CORS(Cross Origin Resource Sharing) preflight request to see if it can access the resource.


#14

ok, so it’s another issue.
Can you show the console??


#15

@anespa Like @uddyvky asked:

Can you show the console?

Based on your logs (res1 null) I think you are not receiving the value from the backend. I don’t think it’s a CORS issue or some backend error response, otherwise (I think) you would receive an error in the http request.

Can you log in your backend to see if your webservice is being called? Seeing the url I think it’s not your backend (you call a third party service). Can you see in the network tab of the developer tools (or in the console) if the method is returning an error?

Are you sure that method is a POST? A method where you getYears() seems more like a GET (this.http.get(...)). Can you call the service (using the url directly, or with Postman or some such service) without ionic and see if it returns correctly?


#16

My console is

I got the json result at last of all the process.
I could not call it using postman service.


#17

@anespa In your code you have http://apps.windows.gov.in/mobservice/index.php/xxx/. It’s not the same url than the one in your screenshot.

First see if

  1. The url you are calling is the right one.
  2. If the http method is correct (GET, POST, …)
  3. If the response status code is correct (200, 2XX)
  4. If the response body is what you want (the json content)

Can you tell me if all these steps are successful?

Also, you should be able to call it using Postman. If you can’t, you should try to solve that first (perhaps the problem is exactly that, and if you discover the problem using Postman the same problem will be solved in Ionic).


#18

The solution to this problem (I talked with @anespa in a private message and found the solution), in case it happens with someone else, is the following:

When using responseType: 'text' (instead of 'json'), it returned the value from the server as a plain string (with responseType: 'json' it returned null). If I tried to parse the string I received an error tough.

The response body from the server was returning a JSON, but the 1st character was invalid (charcode 65279). You can’t see this character, though, so if you logged the response as a string you wouldn’t see it, but if you tried to call JSON.parse() it was given an error (Uncaught SyntaxError: Unexpected token with JSON.parse).

The angular HttpClient probably tries to parse the string when the responseType is json, but, if it can’t, it swallows the exception (I assume) and returns null, making it harder to discover the error.

The solution to this was making a substring with the original string from the 1st valid character onwards (it could be made in other ways):

this.http.post(url, JSON.stringify(obj), { responseType: 'text' }).subscribe(
	body => {
		body = body && body.substring(body.indexOf('[')); // because I know the response is an array
		const obj = body ? JSON.parse(body) : null;
		resolve(obj);
	},
	err => {
		console.log('oops some error in Project Financial year selection');
	}
);