Set Local variable to 1 in subscribe

First of all i wanna apologize for my poor english.
I made this provider for the Get and Post requests:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import 'rxjs/add/operator/toPromise';
import { Observable } from 'rxjs/Observable';
let apiUrl = "http://192.168.1.4/api/v1/"
/*
  Generated class for the AuthServiceProvider provider. 

  See https://angular.io/guide/dependency-injection for more info on providers
  and Angular DI.
*/
@Injectable()
export class AuthServiceProvider { 

  constructor(public http: HttpClient) {
    console.log('Hello AuthServiceProvider Provider');
  }

  public async postData(credentials, type): Promise<any> {
    
    await this.http.post(apiUrl + type, JSON.stringify(credentials)).toPromise();
}
  public getData(type): Observable<any> {

    return this.http.get(apiUrl + type);


  }
 
}

I have a Signup page where user can signup to my app and i when they type all their info and click on that Signup button i wanna check if the email and username isnt already used
on my signup.ts i created to variables:

public usernameTaken=0;
  public emailTaken=0;

to Verifiy if email is taken i used this function:

checkIfExistEmail(){
    var tocheck;
    var check = this.authServiceProvider.getData("userbymail/" + this.userData.email);
    check.subscribe(
      (data) => {
        if(data != null){
          this.emailTaken=1;
        }
      });

  }

To verify if username is taken i used this function:

checkIfExistUsername(){
    var tocheck;
    var check = this.authServiceProvider.getData("user/"+this.userData.username);
    check.subscribe(
      data => {
        if(data != null){
          this.usernameTaken=1;
        }
      });

  }

But when calling these function the variables usernameTaken and emailTaken isnt setting to 1 when the username and email already exist on database, i tried to console.log these variable, inside the subscribe its changing but outside its not.
@bilow

I’m not sure if you are returning some usable content to your subscriptions. But I’ll just give you an example of a implementation. Handle the subscriptions (without logic) in the provider, and keep your “page” simple. When the data is returned you can do the checks and other logic you desire…

auth-service.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable()
export class AuthServiceProvider {
  private apiUrl: string = "http://localhost";

  constructor(
    private http: HttpClient,
  ) { }

  public postData(path, data): Promise<any> {
    return new Promise((resolve, reject) => {
      this.http.post(this.apiUrl + path, JSON.stringify(data)).subscribe((response) => {
        resolve(response);
      }, (err) => {
        reject(err);
      })
    })
      .catch((err) => {
        throw err;
      });
  }

  public getData(path): Promise<any> {
    return new Promise((resolve, reject) => {
      this.http.get(this.apiUrl + path).subscribe((response) => {
        resolve(response);
      }, (err) => {
        reject(err);
      })
    })
      .catch((err) => {
        throw err;
      });
  }
}

And this is how you should/could implement it (your functions):
yourPage.ts

  private checkIfExistEmail(email: string) {
    this.authSrv.getData("/checkExistEmail/" + email)
      .then((result) => {
        if (result.taken) {
          console.log("email is taken");
        } else {
          console.log("email is available");
        }
      }, (err) => {
        console.log("Couldn't check email");
      });
  }

  private checkIfExistUsername(username: string) {
    this.authSrv.getData("/checkExistUsername/" + username)
      .then((result) => {
        if (result.taken) {
          console.log("username is taken");
        } else {
          console.log("username is available");
        }
      }, (err) => {
        console.log("Couldn't check username");
      });
  }

I dislike virtually everything about the provider in the previous post. It is full of needless complexity and provides very little value.

Providers should provide Observables of business interfaces, and look more like this:

interface Customer {
  id: string;
  name: string;
}

interface Order {
  product: string;
  quantity: number;
}

class OrderProvider {
  constructor(private _http: HttpClient) {}
  allCustomers(): Observable<Customer[]> {
    return this._http.get<Customer[]>(api);
  }
  customerByName(name: string): Observable<Customer> {
    return this._http.get<Customer>(api, {params: {name: name}});
  } 

What isn’t here:

  • explicit construction of Promises
  • any
  • generic methods that expose any details of where this information is coming from (such as backend API URL fragments)

Clients of providers should not know or need to care about how the provider does its work. They should be able to treat these providers as pure oracles. This makes app code much cleaner and easier to read, and also allows centralizing any changes to how the data is fetched or stored.

1 Like

This should be a stickied post.

1 Like

Hi @rapropos,
I’m a bit novice in TypeScript / Ionic. Been using it for a couple months now and this is what I’ve seen so far.

Reading your post does make me think in a better way and please do advice me and others about better practices on this subject. But… I’m getting more and more the idea that the so-called “expert/tutorial sites” actually don’t know a damn thing correct. (My apologies for the real pros) Well, maybe I’m overreacting a bit, but… As far as I’ve seen, I think 99% of the (top 10 found) tutorials online do implement a generic http service like I’ve done in my example. Even the Ionic Super Starter uses a generic http service. How can the beginners learn the right thing then?

Could you please, at least, point me to a direction where I can see more of best practices as you’d advice.
Or even better. Can’t you provide a Super Starter example of how you would have done it? It would make it easier for us to start learning the right way.

I think a lot of people would benefit and be thankfull for that.

Thank you for your interest and time…

This is not Working, im trying with a username and email that exist in DB and its says that it doesnt exist :confused:

I think this is largely true. But also, consider @joshmorony, who might be the best Ionic blogger. I’m sure he “knows better,” but he takes code shortcuts, because he needs to produce simple projects that work correctly and that fit in the size of a blog post. You need to take any blog post as a suggestion, not as a recipe for coding in exactly the same way. Your app is almost certainly larger and more complicated than anything on a blog.

Books on Angular – at least the couple I’ve seen – have much better code style than blog posts. Eventually, you’ll get to a point where you need to spend money to get to the next level. If you can, I’d recommend you spend money now, so you don’t have to unlearn bad habits later. i can personally recommend books by fullstack.io and the video content of egghead.io.

1 Like

John Papa is probably the Strunk and White of Angular, and the current version of his style guide is here. Section 08-01 deals with this specific issue of how to structure services:

Do refactor logic for making data operations and interacting with data to a service.

Do make data services responsible for XHR calls, local storage, stashing in memory, or any other data operations.

Why? The component’s responsibility is for the presentation and gathering of information for the view. It should not care how it gets the data, just that it knows who to ask for it. Separating the data services moves the logic on how to get it to the data service, and lets the component be simpler and more focused on the view.

Why? This makes it easier to test (mock or real) the data calls when testing a component that uses a data service.

Why? The details of data management, such as headers, HTTP methods, caching, error handling, and retry logic, are irrelevant to components and other data consumers.

A data service encapsulates these details. It’s easier to evolve these details inside the service without affecting its consumers. And it’s easier to test the consumers with mock service implementations.

So the fact that “api/customer?name=ralph” is involved in fetching a customer by name should be completely isolated within the service, which can’t be done if publicly accessible methods require URL fragment parameters. Clients of that service shouldn’t even know that HTTP is involved at all, because maybe at some point in the future it won’t necessarily be (if you add an offline mode, for example).

1 Like
  ...

  constructor(private _http: HttpClient) {}

  ...

Angular Style Guide - Properties and Methods

Do use lower camel case to name properties and methods. Avoid prefixing private properties and methods with an underscore.

See: https://angular.io/guide/styleguide#properties-and-methods

I could get on board with that rule if access control could actually be enforced in JavaScript. Since it can’t, I find value in the leading underscore naming convention. It allows me to document what properties should not be accessed from outside, and recognize this even at runtime. When I am looking at an OrderProvider in a console, I know that its _http member should not be referenced in client code. Same goes for a hypothetical _fleshOutCustomer() helper function that might be referenced internally from both allCustomers() and customerByName() in order to transform customers from the format received from the backend into what the page wants.

For example, let’s say Order has a customerId field when it comes from the backend. The page is more interested in displaying the customer name than the id, and doesn’t want to have to keep round-tripping to fetch these things. _fleshOutOrder() could populate a customerName field in each Order using an internal cache of Customer objects. Having it in a helper function makes the service more DRY, but clients of the service should not be needing to know anything about this.

1 Like

Anyone have an idea of how i can resolve my problem?