0

I have a function called getPuzzle() that calls an API to get data. I want to use that data to modify a div. The issue is that this is all done in the constructor and so the html hasn't been loaded yet.

So I put the code that modifys the html into ionViewDidEnter, however then it runs before the call to the API and it's missing the data this.puzzle

How do I not run this code until the HTML has loaded completely and AFTER the API call?

ngOnInit() {
    this.getPuzzle();
  }

getPuzzle() {
      //Get puzzle info
      this.puzzlesService.getPuzzle().subscribe((data) => {
        this.puzzleType = this.puzzlesService.puzzleType;
        this.puzzle = this.puzzlesService.puzzle;
      });
  }

ionViewDidEnter() {
    //Set first tab
    if (this.puzzleType == 'text') {
      new Vara("#text", "assets/fonts/vara/Satisfy/SatisfySL.json", [{
        text: this.puzzle,
        delay: 2000,
        x: 2
      }], {
        fontSize: 25,
        strokeWidth: 1.5,
        duration: 15000,
        color: "black"
      });
    }

  }
3
  • Run it inside API call. this.puzzle = this.puzzlesService.puzzle; }); after this line. Commented Sep 24, 2021 at 17:35
  • the HTML isn't loaded at that time and it can't access the #text id Commented Sep 24, 2021 at 17:36
  • Why are you subscribing to puzzlesService.getPuzzle(), then ignoring the data? Seems fishy! Also, why is this component duplicating at least 3 properties of a service you have access to? getPuzzle, puzzleType, and puzzle exist for both this component and the puzzlesService. Is there a reason for that? Commented Sep 24, 2021 at 18:45

2 Answers 2

1

Quick Solution

This is pretty deep into the well of trying to use RxJS imperatively instead of decoratively (Which is a pretty major code-smell with RxJS). Even so, this is one way to ensure that this.puzzlesService.getPuzzle() inside getPuzzle has emitted before the code after //Set first tab is run.

letsGooooooo = new ReplaySubject();

ngOnInit() {
  this.getPuzzle();
}

getPuzzle() {
  //Get puzzle info
  this.puzzlesService.getPuzzle().subscribe((data) => {
    this.puzzleType = this.puzzlesService.puzzleType;
    this.puzzle = this.puzzlesService.puzzle;

    this.letsGooooooo.next("GOOOOOOO!");

  });
}

ionViewDidEnter() {

  this.letsGooooooo.pipe(
    take(1)
  ).subscribe(_ => {
    //Set first tab
    if (this.puzzleType == 'text') {
      new Vara(
        '#text',
        'assets/fonts/vara/Satisfy/SatisfySL.json',
        [
          {
            text: this.puzzle,
            delay: 2000,
            x: 2,
          },
        ],
        {
          fontSize: 25,
          strokeWidth: 1.5,
          duration: 15000,
          color: 'black',
        }
      );
    }
  });
  
}

More Involved Solution

Fix your service so that puzzlesService cashes the current puzzle and puzzle type as an observable rather than properties. Then you don't need to re-implement all those functions locally.

ngOnInit() {
  // No local version of puzzlesService needed
}

ionViewDidEnter() {

  this.puzzlesService.getPuzzle().subscribe(puzzleData => {
    //Set first tab
    if (puzzleData.puzzleType == 'text') { // puzzleData.puzzleType instead of this.puzzleType
      new Vara(
        '#text',
        'assets/fonts/vara/Satisfy/SatisfySL.json',
        [
          {
            text: puzzleData.puzzle, // puzzleData.puzzle instead of this.puzzle
            delay: 2000,
            x: 2,
          },
        ],
        {
          fontSize: 25,
          strokeWidth: 1.5,
          duration: 15000,
          color: 'black',
        }
      );
    }
  });
  
}
Sign up to request clarification or add additional context in comments.

1 Comment

seems i cant use ionviewdidenter either. if i just run the vara code without any variables it's still not long enough before the dom loads and #text still doesn't exist yet. Do you know if there is a wait to wait for a div to exist then execute code?
0

You are facing lifecycle issues. So, a good way that you can do is to call a function after the result of the Api. And on your view you can use an interrogation to avoid data not ready on interpolation {{ puzzle?.text }}

ngOnInit(){
  this.getPuzzle();
}

getPuzzle() {
  //Get puzzle info
  this.puzzlesService.getPuzzle().subscribe((data) => {
    this.puzzleType = this.puzzlesService.puzzleType;
    this.puzzle = this.puzzlesService.puzzle;
    this.updateView(); 👈🏽
  });
}

updateView() {      
  //Set first tab
  if (this.puzzleType == 'text') {
  new Vara("#text", "assets/fonts/vara/Satisfy/SatisfySL.json", [{
    text: this.puzzle,
    delay: 2000,
    x: 2 }],{
    fontSize: 25,
    strokeWidth: 1.5,
    duration: 15000,
    color: "black"
  });
 }
}

2 Comments

this doesn't work. because that function can get called before the HTML has loaded and #text doesn't exist yet
I updated the answer... So, please take a look. And on your view you can use an interrogation to avoid data not ready on interpolation {{ puzzle?.text }}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.