Как обрабатывать асинхронные функции в Angular - PullRequest
0 голосов
/ 21 апреля 2019

//This is a function that is in my data service (in Angular) that basically gets data and puts it in an array
getTenantData() {
  //This is the function that is called by app.component.ts
  //It's job is to get data from the tenants collection and map it to an array called tenants
  this.afs //afs is simply what i named the Firebase db in my constructor
    .collection('tenants')
    .snapshotChanges()
    .subscribe(values => {
      this.tenants = values.map(value => {
        return {
          id: value.payload.doc.id,
          ...value.payload.doc.data()
        };
      });
    });
}


//Then if I create a function that performs some 'work' on the tenants array in another component like so
filterMyArray() {
  this.ad.tenants.filter(values => { //ad is simply what i called the dataservice in the constructor
    if (values.id == 'Some Value') {
      this.filteredArray.push(values);
    }
  });
  console.log(this.filteredArray);
}

//This works fine if I call it using some manual 'after load' approach (like clicking a button)
//Doesn't work if I call it in ngOnInit for instance as tenants hasn't been populated yet
//Throws typeerror cannot read property filter of undefined etc.
//So challenge is how do I get the second function to wait for the first
//Keep in mind first function is in a service not in the same component as second function

Я продолжаю сталкиваться с случаями использования, когда мне приходится иметь дело с асинхронными данными при создании приложения Angular. Я использовал несколько стратегий для решения проблем (асинхронный канал, ngIf, ожидая готовности определенных переменных и т. Д.), Но я чувствую, что что-то упустил. Вот специфика последнего вызова ... У меня есть массив, который заполняется из Firebase. Это делается с помощью вызова функции при загрузке приложения. Давайте назовем массив 'sourceArray'

Затем я хочу выполнить некоторую «работу» над этим массивом, чтобы заполнить элементы содержимого в других компонентах. Например, выполнить «фильтр» для этого массива и создать новый массив из этих результатов.

Проблема, с которой я продолжаю сталкиваться (это только последний пример), состоит в том, что когда я вызываю функцию, которая выполняет «другую работу» в sourceArray, я получаю сообщения об ошибках, говоря, что бла-бла не определена, потому что она не заполнена полностью из базы еще нет. Так что сломать это просто ... Переменная источника, заполняемая чем-то, что занимает некоторое «время» -Хотите работать с этой исходной переменной только после того, как она будет полностью заполнена

Я читал об использовании ловушек жизненного цикла (т.е. помещая зависимую функцию в ловушку, которая запускается после функции источника) и т. Д., И у меня был ограниченный успех при использовании этой стратегии. Также следует отметить, что я «подписываюсь» на данные о базе данных в исходном массиве.

Я также исследовал возможность использования async и await, но не совсем понял, как бы я применил это к этому варианту использования. Любой совет будет оценен и рад предоставить более подробную информацию, если этого недостаточно.

Ответы [ 2 ]

0 голосов
/ 22 апреля 2019

Во-первых, вы не используете метод filter(), как предполагалось. Вы используете его так же, как вы используете map() Вы могли бы просто сделать

filterMyArray() {
 this.filteredArray = this.ad.tenants.filter(values => values.id == 'Some Value');
  console.log(this.filteredArray);
}

Для вашего основного беспокойства вы можете настроить наблюдатель в вашем сервисе, который отфильтровывает исходный массив при его заполнении.

constructor() {
  this.setupWatcher();
}

setupWatcher() {
  interval(1000).pipe(
        switchMap(() => of(this.ad.tenants)),
        filter(response => response && response.length > 0),
        take(1))
        .subscribe((input: Tenants[]) => {
          //do stuff
          this.filterMyArray(input);
        });
}

А потом,

filterMyArray(originalArray: Tenants[]) {
  this.filteredArray = originalArray.filter(values => values.id == 'Some Value');
  console.log(this.filteredArray);
}
0 голосов
/ 21 апреля 2019
// This is how you can await a call from firebase 
// & later do something after call is completed

// write
async function writeData (userId, name, email, imageUrl) {
 await firebase.database().ref('users/' + userId).set({
    username: name,
    email: email,
    profile_picture : imageUrl
  });
  // do something when after is executed
}

// read
async function readData (userId) {
 let response = await firebase.database().ref('/users/' + userId).once('value')
 console.log(response.val())
 // do something after above is executed 
}
...