2

On Angular I write in the html template this code:

<div *ngFor='let itemArray of myObservableArray'>
  <div *ngFor='let item of itemArray | async'>
    {{item.value}}
  </div>
</div>

This is my app.component.ts:

import { Component } from '@angular/core';
import { MyService, MyDataType } from './app.service';
import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular 5';
  myObservableArray: Observable<MyDataType[][]>;

  constructor(private myService: MyService) {
    this.getData(2);
  }

  getData(id: number) {
    if (!this.myObservableArray) {
      this.myObservableArray = new Array<MyDataType[]>();
      this.myObservableArray[id] = this.myService.getData(id);
    }
  }
}

And this is the code of the app.service.ts:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class MyService {

  mydata: MyDataType[] = [
    {"id":1, "value":"value_1_1"},
    {"id":1, "value":"value_1_2"},
    {"id":2, "value":"value_2_1"},
    {"id":2, "value":"value_2_2"},
    {"id":3, "value":"value_3_1"},
    {"id":3, "value":"value_3_2"}
  ];

  constructor() { }

  getData(id: number):Observable<MyDataType[]>
  {
    let data = new Observable<MyDataType[]>(observer => {

          setTimeout(() => {
              observer.next(this.mydata.filter(i => i.id == id));
          }, 4000);
    });
    return data;
  }
}

export class MyDataType
{
  public id: number;
  public value: string;
}

The html template works correctly but I don't understand why the compiler give me this error:

Type 'MyDataType[][]' is not assignable to type 'Observable<MyDataType[][]>'.
      Property '_isScalar' is missing in type 'MyDataType[][]'.
    (property) AppComponent.myObservableArray: Observable<MyDataType[][]>

I think my initialization of the matrix is wrong but being quite new on Angular and TypeScript/JavaScript I would like help on how I can do it. On stackbliz I put the complete DEMO. Thanks.

3
  • 1
    probably because you declare myObservableArray: Observable<MyDataType[][]>; but then use this.myObservableArray = new Array<MyDataType[]>(); Commented Mar 29, 2018 at 15:52
  • @mast3rd3mon your comment does not help me. Could you tell me how I should initialize it if you know? Commented Mar 29, 2018 at 15:58
  • im pretty sure theres an ObservableArray which would be used as myObservableArray: ObservableArray<MyDataType[]>; Commented Mar 29, 2018 at 16:01

3 Answers 3

2

Finally I solved the problem declaring:

myObservableArray: Observable<Array<MyDataType[]>> = new Observable<Array<MyDataType[]>>();

and changing the getData method like the following:

getData(id: number) {
  if (!this.myObservableArray[id]) {
      this.myObservableArray[id] = this.myService.getData(id);
  }
}

and the html template in this way:

<div *ngFor='let item of myObservableArray[2]| async'>
    {{item.value}}
</div>

I have update the DEMO

Sign up to request clarification or add additional context in comments.

Comments

0

I've forked your stackblitz and simplified your solution. Check out Live demo

app.service

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { interval } from 'rxjs/observable/interval';
import { map } from 'rxjs/operators';


@Injectable()
export class MyService {

  mydata: MyDataType[] = [
    {"id":1, "value":"value_1_1"},
    {"id":1, "value":"value_1_2"},
    {"id":2, "value":"value_2_1"},
    {"id":2, "value":"value_2_2"},
    {"id":3, "value":"value_3_1"},
    {"id":3, "value":"value_3_2"}
  ];

  constructor() { }

  // use interval with map instead of setTimeout
  getData(id: number): Observable<MyDataType[]> {
    return interval(5000).pipe(map(i =>this.mydata.filter(i => i.id == id)))
  }
}

app.component

import { Component } from '@angular/core';
import { MyService, MyDataType } from './app.service';
import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular 5';
  myObservableArray: Observable<MyDataType[]>;

  constructor(private myService: MyService) {
    this.getData(2);
  }

  getData(id: number) {
    // you do not needed nested arrays here
    this.myObservableArray = this.myService.getData(id);
  }
}

app.component.html

<p>
    Wait 5 seconds to see some magic happen :)
</p>

<div *ngFor='let item of myObservableArray | async'>
    {{item.value}}
</div>

1 Comment

Thanks for your answer, but you declare myObservableArray: Observable<MyDataType[]>; and this is an array, not a matrix, and isn't what I need.
0
import { Component } from '@angular/core';
import { MyService, MyDataType } from './app.service';
import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular 5';

Here you declare myObservableArray as

Observable<MyDataType[][]

.

  myObservableArray: Observable<MyDataType[][]>;

  constructor(private myService: MyService) {
    this.getData(2);
  }

  getData(id: number) {
    if (!this.myObservableArray) {

But then you try to put

Array<MyDataType[]>() 

into it.

      this.myObservableArray = new Array<MyDataType[]>();
      this.myObservableArray[id] = this.myService.getData(id);
    }
  }
}

You can't put an

Array<MyDataType[]> 

into an

Observable<MyDataType[][]

This is what the compiler is trying to tell you.

2 Comments

Thanks for your answer. Finally I solved the problem declaring: myObservableArray: Observable<Array<MyDataType[]>> = new Observable<Array<MyDataType[]>>() and adapting the code.
Glad to hear that. It was a nice gesture if you would mark this post as solution, though. :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.