Angular 2 (ng2) с использованием асинхронного канала в [class.whatever]

Я работаю над приложением angular 2, и в одном из моих компонентов у меня есть следующее:

<p class="newNode">
  <input [(ngModel)]="formNode.id" placeholder="id">
  <input [(ngModel)]="formNode.name" placeholder="name">
  <input [(ngModel)]="formNode.type" placeholder="image">
  <button (click)="addNode()">Add</button>
</p>

<app-node-info *ngFor="let node of ((nodesService.observable | async) | immutableMapOfMaps)"
  [node]="node"
  [removeNode]="removeNode.bind(this)"
  [class.active] = "(viewService.observable | async).get('currentNode') === node.id"
  (click) = "viewService.setCurrentNode(node.id)">
</app-node-info>

Отлично работает в браузере, но когда я пытаюсь связать свой соответствующий ts-файл, я получаю эту ошибку линтинга: «Метод« async », к которому вы пытаетесь получить доступ, не существует в объявлении класса. (No-access-missing- member) 'at: '11, 21 "

Код моего компонента выглядит следующим образом:

import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { clone } from 'ramda';
import { UUID } from 'angular2-uuid';

import { StateService } from '../state.service';

import { D3Node } from '../../non-angular/interfaces';
import { NodesService, ViewService } from '../../non-angular/services-helpers';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-list-of-nodes',
  styleUrls: ['./list-of-nodes.component.css'],
  templateUrl: './list-of-nodes.component.html',
})
export class ListOfNodesComponent implements OnInit {
  formNode: D3Node;
  /**
   * The injected service from ./state.service
   */
  private nodesService: NodesService;
  private viewService: ViewService;

  constructor(state: StateService) {
    this.nodesService = state.twiglet.nodes;
    this.viewService = state.view;
  }

  ngOnInit () {
    this.formNode = {
      id: UUID.UUID(),
      name: (Math.random().toString(36) + '00000000000000000').slice(2, 6),
      type: (Math.random().toString(36) + '00000000000000000').slice(2, 3),
    };
  }

  addNode () {
    this.nodesService.addNode(clone(this.formNode));
    this.formNode = {
      id: UUID.UUID(),
      name: (Math.random().toString(36) + '00000000000000000').slice(2, 6),
      type: (Math.random().toString(36) + '00000000000000000').slice(2, 3),
    };
  }

  removeNode (node: D3Node) {
    this.nodesService.removeNode(node);
  }

}

Это какой-то тип антипаттерна для использования асинхронного канала в чем-то другом, кроме ngFor?

Я знаю, что могу подписаться на наблюдаемое и установить response = для некоторой локальной переменной, а затем сравнить это вместо использования асинхронного канала в [class.active], но я бы предпочел не делать что-то в моем файле .ts, что я могу просто сделать в моем html файле.

Есть ли способ обойти эту ошибку, чтобы линтер не кричал на меня? У меня есть хуки предварительной фиксации github, которые проверяют линтинг, поэтому мне нужно постоянное решение. Я действительно понял, что могу поставить // tslint:disable-line в строке, которая говорит об обнаружении изменений (строка 11) и исправляет это, но я не знаю почему.


person Ben Hernandez    schedule 19.12.2016    source источник
comment
для какого файла отображается ошибка? - Я не уверен, следует ли вам запускать ts-linter для своих файлов-шаблонов, в конце концов, угловое выражение не является полностью машинописным   -  person olsn    schedule 20.12.2016
comment
Ошибка отображается на name.component.ts, я не проверяю файлы своих шаблонов. Однако, если я удалю строку [class.active] = "(viewService.observable | async).get('currentNode') === node.id" из файла шаблона, линтинг пройдет. Это то, что для меня так странно, как будто tslint каким-то образом импортирует шаблон.   -  person Ben Hernandez    schedule 20.12.2016
comment
Это действительно странно - когда делают линтинг? Вы используете webpack, а линтинг выполняется в предзагрузчике? Или когда-нибудь во время упаковки и т. Д.? Также интересно, что он не выделяет другие варианты использования async   -  person olsn    schedule 20.12.2016
comment
И мой линтер в коде VS, и когда я запускаю `tslint \ src / ** / *. Ts \` в моем терминале, выдает ту же ошибку.   -  person Ben Hernandez    schedule 21.12.2016


Ответы (3)


Не уверен, что это решит проблему, но выражения-шаблоны могут быстро запутаться, вы можете сделать что-то вроде этого:

<app-node-info ...
    [class.active]="(currentNode | async) == node.id">
</app-node-info>

Контроллер:

export class ListOfNodesComponent implements OnInit {
  formNode: D3Node;
  /**
   * The injected service from ./state.service
   */
  private nodesService: NodesService;
  private viewService: ViewService;

  private currentNode: Observable<any>;

  constructor(state: StateService) {
    this.nodesService = state.twiglet.nodes;
    this.viewService = state.view;

    currentNode = this.viewService.observable
      .map(val => val.get('currentNode'));
  }
person olsn    schedule 20.12.2016
comment
Ценить это. Я думал просто вставить его в контроллер, но тогда я теряю преимущества OnPush, которые у меня есть, когда я работал с наблюдаемыми и неизменяемыми. Я, вероятно, вытащу сам сервис из компонента и просто вытолкну переменную из подписки с помощью @Input (), я просто не мог понять, почему у него возникли проблемы с линтингом. - person Ben Hernandez; 21.12.2016
comment
Значит, перемещение частей асинхронной логики к контроллеру ничего не изменило? Я не видел этого раньше, если вы найдете решение, разместите его здесь. - Может быть, в качестве последнего кадра: вы используете === в шаблоне, имеет ли == какое-либо значение? - person olsn; 21.12.2016
comment
Нет, все работало нормально, когда я переместил асинхронный режим в контроллер в качестве подписки. Мне просто любопытно, почему я не могу сделать это так, как у меня есть. - person Ben Hernandez; 21.12.2016
comment
В своем ответе я не перемещал подписку в контроллер - я просто переместил туда некоторые части потока, асинхронный режим все еще находится в шаблоне - не уверен, почему это работает с tslint, но он чище - person olsn; 21.12.2016

У меня была такая же проблема, и я смог избавиться от жалобы линтера с помощью оператора безопасной навигации, подобного этому. Для вас это может выглядеть так.

(viewService.observable | async)?.get('currentNode') === node.id

Изменить: обнаружил отчет об ошибке в codelyzer версии 2.0.0-beta.1 с no-access-missing-member config установлено значение true. Мне кажется, это случай. Кажется, это будет исправлено в более поздних версиях, хотя я еще не пробовал.

person Artur Aleksanyan    schedule 30.01.2017

Я думаю, что есть открытая проблема, которую нужно исправить в codelyzer. https://github.com/angular/angular-cli/issues/4351

Но до тех пор в качестве обходного пути вы можете сделать это в своем компоненте, чтобы исправить проблему с ворсом:

// TODO: fix this later
async: any;

constructor(..) {..}
person Vik    schedule 12.07.2017