কৌণিক 2 - মডেল পরিবর্তনের পরে আপডেট হচ্ছে না দেখুন


128

আমার একটি সাধারণ উপাদান রয়েছে যা প্রতি কয়েক সেকেন্ডে একটি রেস্ট এপিআই কল করে এবং কিছু জেএসএন ডেটা ফিরে পেয়েছে। আমি আমার লগের বিবৃতি এবং নেটওয়ার্ক ট্র্যাফিক থেকে দেখতে পাচ্ছি যে JSON ডেটা ফিরিয়ে দেওয়া হচ্ছে এবং আমার মডেলটি আপডেট হচ্ছে, তবে দৃশ্যটি পরিবর্তন হচ্ছে না।

আমার উপাদানটি দেখে মনে হচ্ছে:

import {Component, OnInit} from 'angular2/core';
import {RecentDetectionService} from '../services/recentdetection.service';
import {RecentDetection} from '../model/recentdetection';
import {Observable} from 'rxjs/Rx';

@Component({
    selector: 'recent-detections',
    templateUrl: '/app/components/recentdetection.template.html',
    providers: [RecentDetectionService]
})



export class RecentDetectionComponent implements OnInit {

    recentDetections: Array<RecentDetection>;

    constructor(private recentDetectionService: RecentDetectionService) {
        this.recentDetections = new Array<RecentDetection>();
    }

    getRecentDetections(): void {
        this.recentDetectionService.getJsonFromApi()
            .subscribe(recent => { this.recentDetections = recent;
             console.log(this.recentDetections[0].macAddress) });
    }

    ngOnInit() {
        this.getRecentDetections();
        let timer = Observable.timer(2000, 5000);
        timer.subscribe(() => this.getRecentDetections());
    }
}

এবং আমার দৃষ্টিভঙ্গি দেখে মনে হচ্ছে:

<div class="panel panel-default">
    <!-- Default panel contents -->
    <div class="panel-heading"><h3>Recently detected</h3></div>
    <div class="panel-body">
        <p>Recently detected devices</p>
    </div>

    <!-- Table -->
    <table class="table" style="table-layout: fixed;  word-wrap: break-word;">
        <thead>
            <tr>
                <th>Id</th>
                <th>Vendor</th>
                <th>Time</th>
                <th>Mac</th>
            </tr>
        </thead>
        <tbody  >
            <tr *ngFor="#detected of recentDetections">
                <td>{{detected.broadcastId}}</td>
                <td>{{detected.vendor}}</td>
                <td>{{detected.timeStamp | date:'yyyy-MM-dd HH:mm:ss'}}</td>
                <td>{{detected.macAddress}}</td>
            </tr>
        </tbody>
    </table>
</div>

আমি দেখতে পাচ্ছি console.log(this.recentDetections[0].macAddress)যে সাম্প্রতিক নির্দেশসমূহ অবজেক্টটি আপডেট করা হচ্ছে, তবে আমি পৃষ্ঠাটি পুনরায় লোড না করা পর্যন্ত দৃশ্যের টেবিলটি কখনই পরিবর্তন হয় না।

আমি এখানে কী ভুল করছি তা দেখার জন্য আমি সংগ্রাম করছি। কেউ সাহায্য করতে পারেন?


: আমি আরো পরিষ্কার এবং কম জটিল করতে কোডে সুপারিশ stackoverflow.com/a/48873980/571030
glukki

উত্তর:


214

এটি হতে পারে যে আপনার সেবার কোডটি কোনওভাবে অ্যাংুলারের অঞ্চল থেকে বিচ্ছিন্ন হয়ে যায়। এটি পরিবর্তন সনাক্তকরণ বিরতি দেয়। এই কাজ করা উচিত:

import {Component, OnInit, NgZone} from 'angular2/core';

export class RecentDetectionComponent implements OnInit {

    recentDetections: Array<RecentDetection>;

    constructor(private zone:NgZone, // <== added
        private recentDetectionService: RecentDetectionService) {
        this.recentDetections = new Array<RecentDetection>();
    }

    getRecentDetections(): void {
        this.recentDetectionService.getJsonFromApi()
            .subscribe(recent => { 
                 this.zone.run(() => { // <== added
                     this.recentDetections = recent;
                     console.log(this.recentDetections[0].macAddress) 
                 });
        });
    }

    ngOnInit() {
        this.getRecentDetections();
        let timer = Observable.timer(2000, 5000);
        timer.subscribe(() => this.getRecentDetections());
    }
}

পরিবর্তন সনাক্তকরণের জন্য অনুরোধ করার অন্যান্য উপায়ের জন্য দেখুন কৌণিকের মধ্যে ম্যানুয়ালি পরিবর্তনের পরিবর্তন সনাক্তকরণ দেখুন

পরিবর্তনের সনাক্তকরণের অনুরোধ করার বিকল্প উপায়গুলি

ChangeDetectorRef.detectChanges()

তাত্ক্ষণিকভাবে বর্তমান উপাদান এবং এর শিশুদের জন্য পরিবর্তন সনাক্তকরণ চালানো

ChangeDetectorRef.markForCheck()

পরের বার কৌণিক পরিবর্তন সনাক্তকরণ চালায় বর্তমান উপাদান অন্তর্ভুক্ত করতে

ApplicationRef.tick()

পুরো অ্যাপ্লিকেশন জন্য পরিবর্তন সনাক্তকরণ চালানো


9
আরেকটি বিকল্প হ'ল চেঞ্জডেক্টরআরফ ইনজেকশন করা এবং এর cdRef.detectChanges()পরিবর্তে কল করা zone.run()। এটি আরও কার্যকর হতে পারে, যেহেতু এটি পুরো উপাদান গাছের মতো পরিবর্তন সনাক্তকরণ চালায় zone.run()না।
রাজকক

1
একমত। কেবলমাত্র detectChanges()যদি আপনি যে কোনও পরিবর্তনগুলি উপাদান এবং এর বংশধরের কাছে স্থানীয় হন তবেই ব্যবহার করুন । আমার বোধগম্যতা যা detectChanges()উপাদান এবং তার বংশধরদের চেক করবে , কিন্তু zone.run()এবং ApplicationRef.tick()সম্পূর্ণ উপাদান গাছটি পরীক্ষা করবে।
রাজকক

2
ঠিক আমি যা খুঁজছিলাম তা ব্যবহার করে @Input()বুঝা যায় না এবং কাজ করে না।
ইয়র্চ

15
কেন আমরা এই সমস্ত ম্যানুয়াল স্টাফগুলি প্রয়োজন বা কেন কৌণিক 2 দেবতারা এগুলি প্রয়োজনীয় রেখে গিয়েছিল তা আমি সত্যিই বুঝতে পারি না। @ ইনপুটটির অর্থ কেন এই নয় যে মূল উপাদানটি তার পরিবর্তিত ডেটার উপর নির্ভর করে যা পিতামণ্ডল উপাদান যা বলেছে তার উপর সত্যই নির্ভরশীল? এটি চূড়ান্তভাবে অবহেলিত বলে মনে হচ্ছে যে এটি কেবল কাজ করে না। আমি কী মিস করছি?

13
আমার জন্য কাজ করেছেন। তবে এটি কেন অন্যরকম আমার কেন অনুভূতি কৌণিক কাঠামো বিকাশকারীরা কৌণিক কাঠামোর জটিলতায় হারিয়ে গেছে। অ্যাপ্লিকেশন বিকাশকারী হিসাবে কৌণিক ব্যবহার করার সময় আপনাকে কীভাবে কৌণিক এটি করে বা এটি করে এবং উপরের দিকে জিজ্ঞাসা করা সম্পর্কিত কাজের মতো কাজগুলি কীভাবে তা বোঝার জন্য আপনাকে অনেক সময় ব্যয় করতে হবে। Terrrible !!
কার্ল

32

এটা মূলত @Mark Rajcok কাছ থেকে মন্তব্য একটি উত্তর, কিন্তু আমি তা এখানে স্থান থেকে একটি পরীক্ষা এবং ব্যবহার করে একটি সমাধান হিসেবে কাজ করেন যেমন চান ChangeDetectorRef , আমি একটি ভাল এখানে বিন্দু দেখুন:

অন্য বিকল্প হ'ল ইনজেকশন ChangeDetectorRefএবং এর cdRef.detectChanges()পরিবর্তে কল করা zone.run()। এটি আরও কার্যকর হতে পারে, যেহেতু এটি পুরো উপাদান গাছের মতো পরিবর্তন সনাক্তকরণ চালায় zone.run()না। - মার্ক রাজকক

কোড অবশ্যই হতে হবে:

import {Component, OnInit, ChangeDetectorRef} from 'angular2/core';

export class RecentDetectionComponent implements OnInit {

    recentDetections: Array<RecentDetection>;

    constructor(private cdRef: ChangeDetectorRef, // <== added
        private recentDetectionService: RecentDetectionService) {
        this.recentDetections = new Array<RecentDetection>();
    }

    getRecentDetections(): void {
        this.recentDetectionService.getJsonFromApi()
            .subscribe(recent => { 
                this.recentDetections = recent;
                console.log(this.recentDetections[0].macAddress);
                this.cdRef.detectChanges(); // <== added
            });
    }

    ngOnInit() {
        this.getRecentDetections();
        let timer = Observable.timer(2000, 5000);
        timer.subscribe(() => this.getRecentDetections());
    }
}

সম্পাদনা : .detectChanges()ভিতরে সাবসিবি ব্যবহার করে ধ্বংস হওয়া ভিউ: ডিটেন্ড চেঞ্জ ব্যবহার করার চেষ্টা চালিয়ে যেতে পারে

এটির সমাধান করার জন্য unsubscribeআপনাকে উপাদানটি ধ্বংস করার আগে আপনার প্রয়োজন হবে , সুতরাং সম্পূর্ণ কোডটি এর মতো হবে:

import {Component, OnInit, ChangeDetectorRef, OnDestroy} from 'angular2/core';

export class RecentDetectionComponent implements OnInit, OnDestroy {

    recentDetections: Array<RecentDetection>;
    private timerObserver: Subscription;

    constructor(private cdRef: ChangeDetectorRef, // <== added
        private recentDetectionService: RecentDetectionService) {
        this.recentDetections = new Array<RecentDetection>();
    }

    getRecentDetections(): void {
        this.recentDetectionService.getJsonFromApi()
            .subscribe(recent => { 
                this.recentDetections = recent;
                console.log(this.recentDetections[0].macAddress);
                this.cdRef.detectChanges(); // <== added
            });
    }

    ngOnInit() {
        this.getRecentDetections();
        let timer = Observable.timer(2000, 5000);
        this.timerObserver = timer.subscribe(() => this.getRecentDetections());
    }

    ngOnDestroy() {
        this.timerObserver.unsubscribe();
    }

}

this.cdRef.detectChanges (); আমার সমস্যা সমাধান। ধন্যবাদ!
মঙ্গল

আপনার পরামর্শের জন্য ধন্যবাদ তবে একাধিক কল করার পরেও আমি ত্রুটি পেয়েছি: ব্যর্থতা: ত্রুটি: ভিউডাস্ট্রয়েড এরির: ধ্বংস হওয়া ভিউটি ব্যবহারের চেষ্টা করুন: আমার জন্য জোন.আরুন () আমাকে এই ত্রুটি থেকে বেরিয়ে আসতে সহায়তা করে।
শিবম শ্রীবাস্তব

8

ব্যবহার করার চেষ্টা করুন @Input() recentDetections: Array<RecentDetection>;

সম্পাদনা করুন: কেন@Input()গুরুত্বপূর্ণ কারণ আপনার (HTML) দৃশ্যে টাইপ করা বিষয় / JavaScript ফাইলে মান জুড়তে অনুমতি চান। @Input()সাজসজ্জারেরসাথে ঘোষিত মানপরিবর্তন করাহলে দৃশ্য নিজেই আপডেট হবে। যদি কোনও@Input()বা@Output()সাজসজ্জার পরিবর্তন করা হয়, তবেngOnChangesআগমনকারী ট্রিগার করবে এবং দর্শনটি নতুন মান দিয়ে নিজেকে আপডেট করবে। আপনি বলতে পারেন যে@Input()ইচ্ছা দ্বি-মুখী মূল্য আবদ্ধ।

কৌণিক দ্বারা এই লিঙ্কটিতে ইনপুট অনুসন্ধান করুন: আরও তথ্যের জন্য শব্দকোষ

সম্পাদনা: কৌণিক 2 বিকাশ সম্পর্কে আরও জানার পরে, আমি বুঝতে পেরেছি যে@Input()সত্যিই করা সমাধান নয়, এবং মন্তব্যে উল্লিখিত হিসাবে,

@Input() কেবলমাত্র তখন প্রয়োগ হয় যখন উপাদানটির বাইরের অংশ থেকে ডেটা-বাঁধাইয়ের মাধ্যমে ডেটা পরিবর্তন করা হয় (যখন প্যারেন্টে আবদ্ধ ডেটা পরিবর্তিত হয়) যখন উপাদানটির মধ্যে কোড থেকে ডেটা পরিবর্তন করা হয় না।

আপনার যদি @ গন্তারের উত্তরটি দেখুন তবে এটি সমস্যার আরও সঠিক এবং সঠিক সমাধান। আমি এখনও এই উত্তরটি এখানে রাখব, তবে দয়া করে গন্টারের উত্তরটি সঠিক হিসাবে অনুসরণ করুন।


2
ঐটা এটা ছিল. আমি @ ইনপুট () টীকাটি আগে দেখেছি তবে সর্বদা এটি ফর্ম ইনপুটগুলির সাথে যুক্ত করেছিলাম, কখনও ভাবিনি যে এখানে এটির দরকার হবে। চিয়ার্স।
ম্যাট ওয়াটসন

1
অ্যাডভাইটোনাল ব্যাখ্যার জন্য জন ধন্যবাদ আপনি যা যুক্ত করেছেন কেবলমাত্র তখনই প্রয়োগ হয় যখন উপাদানটির বাইরে কোড থেকে ডেটা-বাঁধাইয়ের মাধ্যমে ডেটা পরিবর্তন করা হয় (প্যারেন্টে আবদ্ধ ডেটা পরিবর্তিত হয়) যখন উপাদানটির মধ্যে কোড থেকে ডেটা পরিবর্তন করা হয় না।
গন্টার জ্যাচবাউয়ার

@Input()মূল শব্দটি ব্যবহার করার সময় এখানে একটি সম্পত্তি বাঁধাই থাকে এবং সেই বাইন্ডিংটি নিশ্চিত করে যে মানটি ভিউতে আপডেট হয়েছে। মানটি একটি জীবনচক্র ইভেন্টের অংশ হবে। এই পোস্টে@Input() মূল-শব্দটি সম্পর্কে আরও কিছু তথ্য রয়েছে
জন

ছেড়ে দেব। আমি দেখতে পাচ্ছি না যে এখানে কোনও @Input()জড়িত রয়েছে বা এটি কেন হওয়া উচিত এবং প্রশ্নটি যথেষ্ট তথ্য সরবরাহ করে না। যাইহোক আপনার ধৈর্য জন্য ধন্যবাদ :)
গন্টার Zöchbauer

3
@Input()সমস্যাটির মূলকে আড়াল করে রাখার মতো আরও কাজ করা। সমস্যাগুলি অঞ্চলগুলির সাথে সম্পর্কিত হতে হবে এবং সনাক্তকরণের পরিবর্তন করতে হবে।
ম্যাজিক্রাফটার

2

আমার ক্ষেত্রে, আমার খুব অনুরূপ সমস্যা ছিল। আমি একটি ফাংশনটির ভিতরে আমার দৃষ্টিভঙ্গি আপডেট করছি যা একটি পিতামাত উপাদান দ্বারা আহ্বান করা হয়েছিল, এবং আমার পিতামাতার উপাদানগুলিতে আমি @ ভিউচিল্ড (নামঅফমাইচিল্ডকম্পোন্ট) ব্যবহার করতে ভুলে গেছি। আমি এই বোকা ভুলের জন্য কমপক্ষে 3 ঘন্টা হারিয়েছি। অর্থাত: আমার এই পদ্ধতিগুলির কোনও ব্যবহার করার দরকার নেই :

  • ChangeDetectorRef.detectChanges ()
  • ChangeDetectorRef.markForCheck ()
  • ApplicationRef.tick ()

1
আপনি কীভাবে আপনার নিজের সন্তানের উপাদানটি @ ভিউচিল্ডের সাথে আপডেট করেছেন তা ব্যাখ্যা করতে পারেন? ধন্যবাদ
লুকাস কলম্বো

আমার সন্দেহ,
অভিভাবকরা

1

অঞ্চলগুলি নিয়ে কাজ করার পরিবর্তে এবং সনাক্তকরণের পরিবর্তনের পরিবর্তে - AsyncPipe জটিলতা পরিচালনা করতে দিন handle এটি পর্যবেক্ষণযোগ্য সাবস্ক্রিপশন, আনস-সাবস্ক্রিপশন (মেমরি ফাঁস রোধ করতে) এবং কৌণিক কাঁধে সনাক্তকরণে পরিবর্তন আনবে।

একটি পর্যবেক্ষণযোগ্য করতে আপনার শ্রেণি পরিবর্তন করুন, এটি নতুন অনুরোধের ফলাফল নির্গত করবে:

export class RecentDetectionComponent implements OnInit {

    recentDetections$: Observable<Array<RecentDetection>>;

    constructor(private recentDetectionService: RecentDetectionService) {
    }

    ngOnInit() {
        this.recentDetections$ = Observable.interval(5000)
            .exhaustMap(() => this.recentDetectionService.getJsonFromApi())
            .do(recent => console.log(recent[0].macAddress));
    }
}

এবং অ্যাসিঙ্কপিপ ব্যবহার করতে আপনার দৃষ্টিভঙ্গি আপডেট করুন:

<tr *ngFor="let detected of recentDetections$ | async">
    ...
</tr>

যুক্ত করতে চান, এমন একটি পদ্ধতি দিয়ে পরিষেবা তৈরি করা ভাল যা intervalযুক্তি নেবে এবং:

  • নতুন অনুরোধ তৈরি করুন ( exhaustMapউপরের কোডের মতো ব্যবহার করে );
  • অনুরোধ ত্রুটিগুলি হ্যান্ডেল;
  • অফলাইনে থাকাকালীন ব্রাউজারটিকে নতুন অনুরোধ করা বন্ধ করুন।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.