Это уже зарезервированные имена) Выберите что-то еще

это не повторяющийся вопрос. Видите ли, в SO и Github есть множество вопросов и проблем, которые предписывают мне добавить эту директиву к тегу, который имеет[(ngModel)] директива и не содержится в форме. Если я не добавлю это, я получаю ошибку:

ERROR Error: No value accessor for form control with unspecified name attribute

Хорошо, ошибка исчезнет, ​​если я добавлю этот атрибут туда. Но ждать! Никто не знает, что он делает! И документ Angular вообще не упоминает об этом. Зачем мне нужен аксессор значения, когда я знаю, что он мне не нужен? Как этот атрибут связан со значениями доступа? Что делает эта директива? Что такое вспомогательный метод значения и как его использовать?

И почему все продолжают делать вещи, которые не все понимают? Просто добавьте эту строку кода, и она работает, спасибо, это не способ писать хорошие программы.

А потом. Я читаю не одну нодва огромные гиды о формах в Angularа также раздел оngModel:

https://angular.io/guide/formshttps://angular.io/guide/reactive-formshttps://angular.io/guide/template-syntax#ngModel

И знаешь, что? Ни единого упоминания ни о ценностных методах доступа, ниngDefaultControl, Где это находится?

Ответы на вопрос(1)

Решение Вопроса
[NgDefaultControl]

Сторонние элементы управления требуютControlValueAccessor функционировать с угловатыми формами. Многие из них, как у Полимера<paper-input>веди себя как<input> родной элемент и, следовательно, может использоватьDefaultValueAccessor, ДобавлениеngDefaultControl Атрибут позволит им использовать эту директиву.

<paper-input ngDefaultControl [(ngModel)]="value>

или же

<paper-input ngDefaultControl formControlName="name">

Так что это главная причина, почему этот attrubute был введен.

Это называлосьng-default-control атрибутв альфа-версиях angular2.

ТакngDefaultControl является одним из селекторов дляDefaultValueAccessor директива:

@Directive({
  selector:
      'input:not([type=checkbox])[formControlName],
       textarea[formControlName],
       input:not([type=checkbox])[formControl],
       textarea[formControl],
       input:not([type=checkbox])[ngModel],
       textarea[ngModel],
       [ngDefaultControl]', <------------------------------- this selector
  ...
})
export class DefaultValueAccessor implements ControlValueAccessor {

Что это значит?

Это означает, что мы можем применить этот атрибут к элементу (например, полимерному компоненту), который не имеет своего собственного средства доступа к значениям. Таким образом, этот элемент будет принимать поведение отDefaultValueAccessor и мы можем использовать этот элемент с угловыми формами.

В противном случае вы должны предоставить собственную реализациюControlValueAccessor

ControlValueAccessor

угловатыйдокументы государства

ControlValueAccessor действует как мост между API угловых форм и собственным элементом в DOM.

Давайте напишем следующий шаблон в простом приложении angular2:

<input type="text" [(ngModel)]="userName">

Чтобы понять, как нашиinput выше будет вести себя, нам нужно знать, какие директивы применяются к этому элементу. Здесь angular выдает некоторую подсказку с ошибкой:

Необработанное отклонение обещания: ошибки синтаксического анализа шаблона: невозможно связать с 'ngModel', поскольку оно не является известным свойством 'input'.

Хорошо, мы можем открыть SO и получить ответ: импортFormsModule на ваш@NgModule:

@NgModule({
  imports: [
    ...,
    FormsModule
  ]
})
export AppModule {}

Мы импортировали его, и все работает как задумано. Но что происходит под капотом?

FormsModule экспортирует для нас следующие директивы:

@NgModule({
 ...
  exports: [InternalFormsSharedModule, TEMPLATE_DRIVEN_DIRECTIVES]
})
export class FormsModule {}

После некоторого расследования мы можем обнаружить, что три директивы будут применяться к нашемуinput

1)NgControlStatus

@Directive({
  selector: '[formControlName],[ngModel],[formControl]',
  ...
})
export class NgControlStatus extends AbstractControlStatus {
  ...
}

2)NgModel

@Directive({
  selector: '[ngModel]:not([formControlName]):not([formControl])',
  providers: [formControlBinding],
  exportAs: 'ngModel'
})
export class NgModel extends NgControl implements OnChanges, 

3)DEFAULT_VALUE_ACCESSOR

@Directive({
  selector:
      `input:not([type=checkbox])[formControlName],
       textarea[formControlName],
       input:not([type=checkbox])formControl],
       textarea[formControl],
       input:not([type=checkbox])[ngModel],
       textarea[ngModel],[ngDefaultControl]',
  ,,,
})
export class DefaultValueAccessor implements ControlValueAccessor {

NgControlStatus Директива просто манипулирует такими классами, какng-valid, ng-touched, ng-dirty и мы можем опустить это здесь.

DefaultValueAccesstor обеспечиваетNG_VALUE_ACCESSOR токен в массиве провайдеров:

export const DEFAULT_VALUE_ACCESSOR: any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => DefaultValueAccessor),
  multi: true
};
...
@Directive({
  ...
  providers: [DEFAULT_VALUE_ACCESSOR]
})
export class DefaultValueAccessor implements ControlValueAccessor {

NgModel директива внедряет в конструкторNG_VALUE_ACCESSOR токен, который был объявлен на том же элементе хоста. ,

export NgModel extends NgControl implements OnChanges, OnDestroy {
 constructor(...
  @Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) {

В нашем случаеNgModel будет вводитьDefaultValueAccessor, И теперь директива NgModel вызывает совместноsetUpControl функция:

export function setUpControl(control: FormControl, dir: NgControl): void {
  if (!control) _throwError(dir, 'Cannot find control with');
  if (!dir.valueAccessor) _throwError(dir, 'No value accessor for form control with');

  control.validator = Validators.compose([control.validator !, dir.validator]);
  control.asyncValidator = Validators.composeAsync([control.asyncValidator !, dir.asyncValidator]);
  dir.valueAccessor !.writeValue(control.value);

  setUpViewChangePipeline(control, dir);
  setUpModelChangePipeline(control, dir);

  ...
}

function setUpViewChangePipeline(control: FormControl, dir: NgControl): void 
{
  dir.valueAccessor !.registerOnChange((newValue: any) => {
    control._pendingValue = newValue;
    control._pendingDirty = true;

    if (control.updateOn === 'change') updateControl(control, dir);
  });
}

function setUpModelChangePipeline(control: FormControl, dir: NgControl): void {
  control.registerOnChange((newValue: any, emitModelEvent: boolean) => {
    // control -> view
    dir.valueAccessor !.writeValue(newValue);

    // control -> ngModel
    if (emitModelEvent) dir.viewToModelUpdate(newValue);
  });
}

И вот мост в действии:

NgModel устанавливает контроль(1) и звонкиdir.valueAccessor !.registerOnChange метод.ControlValueAccessor сохраняет обратный звонок вonChange(2) свойство и запускает этот обратный вызов, когдаinput событие происходит(3), И наконецupdateControl функция вызывается внутри обратного вызова(4)

function updateControl(control: FormControl, dir: NgControl): void {
  dir.viewToModelUpdate(control._pendingValue);
  if (control._pendingDirty) control.markAsDirty();
  control.setValue(control._pendingValue, {emitModelToViewChange: false});
}

где угловые звонки формируют APIcontrol.setValue.

Это короткая версия того, как это работает.

 yurzui28 сент. 2017 г., 14:20
Это уже зарезервированные имена) Выберите что-то еще
 Gherman28 сент. 2017 г., 14:19
Это именно то, что я делал. Но я назвал свою «ценность» какngModel и Angular начал выдавать ошибку и запрашивать с ControlValueAccessor.
 yurzui28 сент. 2017 г., 14:17
Если вы не используете этот компонент с угловыми формами, вы можете просто создать свою собственную двустороннюю привязку, например@Input() value; @Output() valueChange: EventEmitter<any> = new EventEmitter(); а потом просто использовать[(value)]="someProp"
 Gherman28 сент. 2017 г., 14:14
Я только что сделал@Input() ngModel а также@Output() ngModelChange для двунаправленной привязки и я подумал, что моста должно хватить. Это похоже на то, чтобы делать то же самое совершенно другим способом. Может быть, я не должен называть свое полеngModel?

Ваш ответ на вопрос