2016-05-10 7 views
4

サービスからのデータを表示するコンポーネントをAngular 2で作成しようとしています。このサービスは基本的に、ユーザーからの入力を受けてjsonファイルからいくつかのデータをロードします。私はコンポーネントを更新しようとしていますが、私のサービスからイベントを送信した後にzone.run()を呼び出さない限り、変更を認識していないようです。コンポーネントに対して次のように私のコードは...角2 - なぜzone.run()が必要ですか?

@Component({ 
    selector: 'assess-asset-group', 
    directives: [AssetComponent, AssetHeaderComponent, NgFor, NgIf], 
    template: ` 

      <div *ngIf="assetService.schema != null"> 
       <div class="asset-group" *ngFor="#assetTypeName of assetService.schema.assetTypeNames"> 
        <div class="asset-type-title"><span>{{assetService.schema.assetTypes[assetTypeName].name}}s</span></div> 
        <table class="asset-group-table" cellpadding=0 cellspacing=0> 
         <thead> 
          <tr assess-asset-header [assetType]="assetService.schema.assetTypes[assetTypeName]"></tr> 
         </thead> 
         <tbody> 
          <tr assess-asset *ngFor="#asset of assetService.assetsForType(assetTypeName)" [asset]="asset"></tr> 
         </tbody> 
        </table> 
        <button class="new-asset-btn" (click)="assetService.addAsset(assetTypeName)">New</button> 
       </div> 
      </div>`, 
    providers: [provide(AssetService, {useValue: injector.get(AssetService)})] 
}) 
export class AssetGroupComponent { 

    public assetService: AssetService; 
    public zone: NgZone; 

    constructor(@Inject(AssetService) assetService: AssetService, zone: NgZone) { 
     this.assetService = assetService; 
     this.zone = zone; 
    } 

    ngOnInit() { 
     this.assetService.proejectLoadedEmitter.subscribe((e) => { this.zone.run(() => { }) }); 
    } 

    ngOnDestroy() { 
     this.assetService.proejectLoadedEmitter.unsubscribe(); 
    } 
} 

は私が何か間違ったことをやっている場合、またはこれは私がビューを更新するために何をする必要があるかありますか?

UPDATE - AssetServiceクラス

@Injectable() 
export class AssetService{ 
    public assets: Assets.Asset[] = []; 
    public assetTypeDefinitions: any = null; 

    public schema: Schema = null; 
    public assetsAsObj: any = null; // Asset file loaded as object 

    @Output() proejectLoadedEmitter: EventEmitter<any> = new EventEmitter(); 

    constructor(){ 
    } 

    public loadProject(config: Project){ 
     // Load schema 
     // populate AssetTypeDefinitions as object keyed by type 
     let data = fs.readFileSync(config.schemaPath, 'utf8'); 
     if (!data) { 
      utils.logError("Error reading schema file"); 
      return; 
     } 
     let struc = fs.readFileSync(config.structurePath, 'utf8'); 
     if (!struc) { 
      utils.logError("Error reading structure file"); 
      return; 
     } 

     this.schema = new Schema(JSON.parse(data), struc); 
     this.readAssets(config.assetFilePath); 
    } 

    /** 
    * @brief Adds a new asset to the assets array 
    * @details Constructs the asset based on the type and populates 
    * its fields with appropreiate default values 
    * 
    * @param type The type of the asset - specified in the schema 
    */ 
    public addAsset(type: string): void { 
     // Need to make sure there is a loaded type definition for the specified type 
     if(!this.schema.assetTypes.hasOwnProperty(type)){ 
      utils.logError("Error occured during call to addAsset - type \"" + type + "\" is not specified in the loaded schema"); 
      return; 
     } 
     // Creeate a new asset object - passing in the type definition from the schema 
     this.assets.push(new Assets.Asset(this.schema.assetTypes[type])); 
    } 

    /** 
    * Write the current assets to a file using the specified format 
    * If the outputPasth isn't specied try and load it from the project.json file 
    */ 
    public writeAssets(format:AssetWriteFormat, outputPath?: string) : void { 

     var outStructureStr = this.schema.structureStr; 
     // insert AS properties from schema into output assets 
     this.schema.properties.forEach(prop => { 
      outStructureStr = outStructureStr.replace(new RegExp('"' + prop +'"', 'i'), this.retriveValueForSchemaProperty(prop)); 
     }); 

     fs.writeFileSync("C:/Projects/Assess/assets.json", outStructureStr); 
    } 

    public readAssets(inputPath?: string) : void{ 
     let assetsStr = fs.readFileSync(inputPath, 'utf8'); 

     let strucToAssetMap = {}; 
     let strucObj = JSON.parse(this.schema.structureStr); 
     this.schema.properties.forEach(p => { 
      strucToAssetMap[p] = this.findValueInObject(strucObj, p).reverse(); 
     }); 

     // @TODO Load custom properties 
     let assetsObj = JSON.parse(assetsStr); 
     var c = null; 
     strucToAssetMap["AS_ASSETS"].forEach(p => { 
      if(c == null){ 
       c = assetsObj[p]; 
      }else{ 
       c = c[p]; 
      } 
     }); 
     c.forEach((asset) => { 
      let a:Assets.Asset = new Assets.Asset(this.schema.assetTypes[asset.type], asset); 
      this.assets.push(a); 
     }); 
     console.log(this.assets); 
     this.proejectLoadedEmitter.emit(null); 
    } 

    public assetsForType(type:string): Assets.Asset[]{ 
     var ret: Assets.Asset[] = []; 
     for(let idx in this.assets){ 
      if(this.assets[idx].definition.type === type){ 
       ret.push(this.assets[idx]); 
      } 
     } 
     return ret; 
    } 

    public retriveValueForSchemaProperty(property: string) : string{ 
     if(AS_SchemaTypes.indexOf(property) != -1){ 
      switch (property) { 
       case "AS_ASSETS": 
        let outAssets = []; 
        this.assets.forEach((asset) => { 
         let outAsset = {}; 
         outAsset["type"] = asset.definition.type; 

         for (let key in asset.fields) { 
          outAsset[key] = asset.fields[key].value; 
         } 
         outAssets.push(outAsset); 
        }); 
        return JSON.stringify(outAssets, null, "\t"); 
      } 
     }else{ 
      // @TODO Retrive custom properties 
      return '"DDDDDD"'; 
     } 
     return ""; 
    } 

    public findValueInObject(obj: any, property: string, path: any[] = []): any[] { 
     for(let x in obj){; 
      let val = obj[x]; 
      if (val == property){ 
       path.push(x); 
       return path; 
      } 
      else if(val != null && typeof val == 'object'){ 
       let v = this.findValueInObject(val, property, path); 
       if(v != null){ 
        path.push(x); 
        return path; 
       } 
      } 
     } 
     return null; 
    } 
} 
+0

変更検出のための角度使用ゾーン。外部ライブラリによってコードが離れることがあります。角度ゾーンと "ブレーク"変化検出http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html –

答えて

7

これには、使用しているAssetServiceの内部動作に関する知識が必要です。

Angularは、ほとんどの非同期API(addEventListenersetTimeout、...)がパッチされているゾーン内のコンポーネントのコードを実行します。そのような非同期コールバックが発生したときにゾーンがAngularに通知できます。これは、Angularが変化検出を実行しているときです。

AssetServiceを角度外に、またはAssetServiceを他の手段で初期化した場合、Angularsゾーン外のコードを実行すると、発生した非同期コールバックについてAngularは通知されず、変更検出も実行されません。

zone.run(...)では、角度領域内でコードを明示的に実行し、その後に変更検出を実行します。

+0

私のAssetServiceは、 Injector.resolveAndCreate。ただし、loadProject呼び出しをトリガするイベントはElectronメニューから発生しています。 AssetServiceコードを含むように投稿を更新しました。私はあなたが正しいと仮定し、それはクラスがどのように設定されているためにAngularによって監視されていません。これが当てはまる場合、私は問題を解決するために適切なアプローチをとっていますか? – rykeeboy

+0

このような音が原因である可能性があります。イベントハンドラによって実行されるコードに 'zone.run(...)'を使うだけです。 –

+0

電子イベントが発生したときにあなたのサービスのどのメソッドが呼び出されますか? –

0

はないthis.assetService、あなたの意見では、それはおそらくassetService、引数を参照することにより引き起こされ、そしてか?おそらく、zone.run()を呼び出さなければAngularの変更検出がトリガされないことがあります。

関連する問題