semper fi
semper fi

Reputation: 747

data bind not work angular 2

Can't understand why the data not binding on ui, trying to bind array using *ngFor, but nothing is display on ui while the data is exist in array. Here the component code:

import { Component, Injector, OnInit, OnDestroy, Pipe } from '@angular/core'
import { AdvancedPostsService } from '../../services/advanced.posts.service'
import { SpinnerService } from '../../services/spinner.service'
import { PathKey } from '../../helpers/platform.helpers'
import { Router } from '@angular/router'
import { ToolsService } from '../../services/tools.service'
import { YoutubeToolsService } from '../../services/youtube.tools.service'

@Pipe({ name: 'safe' })
@Component({
    selector: 'advanced-post-youtube-step-component',
    templateUrl: '../../templates/advanced-posts-templates/advanced.post.youtube.component.html'
})
export class AdvancedPostYoutubeStep implements OnInit, OnDestroy {

    private postId: number;
    private stepId: number;
    private postType: number;
    videoList: any[] = [];
    private youTubeWatchUrl = "https://www.youtube.com/embed/";
    i = 0;

    constructor(private advancedPostsService: AdvancedPostsService,
        private spinner: SpinnerService,
        private toolsService: ToolsService,
        private injector: Injector,
        private router: Router,
        private youtubeToolsService: YoutubeToolsService) {
        this.injectParentData();
    }

    ngOnInit(): void {
        this.youtubeToolsService.change.on(this.onYoutubeVideosLoaded.bind(this));
        this.youtubeToolsService.initGoogleAuthentication();
        this.spinner.stop();
    }

    onYoutubeVideosLoaded(self: YoutubeToolsService) {
        for (let item of self.videoList) {
            if (item) {
                console.log(item);
                this.videoList.push({
                    id: item.snippet.resourceId.videoId,
                    url: this.youTubeWatchUrl + item.snippet.resourceId.videoId
                });
            }
        }
        console.log(this.videoList);
    }

    ngOnDestroy(): void {
        this.youtubeToolsService.change.off(this.onYoutubeVideosLoaded.bind(this));
        this.spinner.start();
    }

    injectParentData() {
        this.postId = this.injector.get(PathKey.PostId);
        this.stepId = this.injector.get(PathKey.StepId);
        this.postType = this.injector.get(PathKey.PostType);

    }
}

And ui part:

<div class="col-md-6 col-md-offset-3">
    <h3 class="text-center">Select video</h3>

    <div>
        <iframe *ngFor="let video of videoList" type="text/html" class="video-responsive" [src]="video?.url | safe" frameborder="0"></iframe>
    </div>
    <h4>{{videoList.length}}</h4>
</div>

Even videoList.lenth do not displayed. Anyone know what the problem here?

UPDATE YoutubeToolsService code:

import { NgZone, Injectable} from '@angular/core'
import { OperationDataResult } from '../helpers/operation.models'
import { Config } from '../helpers/social.models'
import { LiteEvent } from '../helpers/lite.event'
import { SocialService } from '../services/social.service'


declare var gapi: any;

@Injectable()
export class YoutubeToolsService {

    private loginStatus: any;
    private onChange = new LiteEvent<YoutubeToolsService>();
    get change() { return this.onChange.expose(); }
    videoList: any[] = [];

    requestVideoPlaylist(playlistId) {
        var requestOptions = {
            playlistId: playlistId,
            part: 'snippet',
            maxResults: 10
        };

        var request = gapi.client.youtube.playlistItems.list(requestOptions);
        request.execute(response => {
            var playlistItems = response.result.items;
            if (playlistItems) {

                this.videoList = playlistItems;
                this.onChange.trigger(this);
            }
        });
    }

Upvotes: 1

Views: 142

Answers (1)

Pankaj Parkar
Pankaj Parkar

Reputation: 136174

Basically you are updating view binding variable from outside Angular context. In that case zonejs doesn't understand binding got updated and won't able to perform change detection. That's why in this case you've to run Change Detection cycle your self inside onYoutubeVideosLoaded function. For the same you could use ChangeDetectorRef API & call detectChanges method whenever you want to run Change Detection to update binding manually.

constructor(private ref: ChangeDetectorRef) { }; //inject & import ChangeDetectorRef
//OR
//constructor(private _ngZone: NgZone) { }; //make sure constructor have NgZone

onYoutubeVideosLoaded(self: YoutubeToolsService) {
    //below commented that can be alternative way of doing it
    //this._ngZone.run(() => {
      for (let item of self.videoList) {
        if (item) {
            console.log(item);
            this.videoList.push({
                id: item.snippet.resourceId.videoId,
                url: this.youTubeWatchUrl + item.snippet.resourceId.videoId
            });
        }
      }
      //running CD manually
      this.ref.detectChanges();
    //});
}

Upvotes: 2

Related Questions