【问题标题】:Changing Component Property from Directive in Angular2从Angular2中的指令更改组件属性
【发布时间】:2016-01-18 02:29:24
【问题描述】:

我有一个 Angular 1 应用程序,它使用一个简单的 contentEditable 指令,可以在模板中像这样使用:

<span contenteditable="true"  ng-model="model.property" placeholder="Something">

编辑元素会触发$setViewValue(element.html(),它按预期工作。

我想用类似简洁的模板语法在 Angular2 中制作一些东西。理想情况下,我希望模板看起来像这样:

<span contentEditable="true" [(myProperty)]="name"></span>

其中 'name' 是组件上的一个属性,并让指令在更改时更新组件。我觉得我很接近这个(Plunker Link):

//our root app component
import {Component, Input, Output Directive, ElementRef, Renderer, OnInit} from 'angular2/core'

@Directive({
    selector: '[contentEditable]',
    host: {
        '(blur)': 'update($event)'
    }
})

export class contentEditableDirective implements OnInit {
    @Input() myProperty;
    constructor(private el: ElementRef, private renderer: Renderer){}

    update(event){
      this.myProperty = this.el.nativeElement.innerText;
    }
    ngOnInit(){
        this.el.nativeElement.innerText =  this.myProperty; 
    }
}

如果我传递一个像{name: "someName"} 这样的对象,这个想法是有效的,但是如果只是传递一个属性,它似乎传递的是值,而不是引用,因此绑定不会流回组件。有没有办法做到这一点,仍然允许模板语法不冗长,但仍然允许轻松重用指令。

【问题讨论】:

  • 我要补充一点,如果我向指令添加 2 个输入并将对象和属性名称作为单独的输入传递,我可以做到这一点。我的模板将如下所示:&lt;myElement contentEditable="true" [myobject]="anobject" property="somevalue"&gt; 然后我可以从指令中操作myobject[property]。不过更喜欢更清洁的方式。

标签: angular


【解决方案1】:

指令不知道其父 name 属性。您可以从指令中发出一个事件并在父级中捕获它。检查这个例子

@Directive({
    selector: '[contentEditable]',
    host: {
        '(input)': 'update($event)' // I changed it to input to see the changes immediatly
    }
})
export class contentEditableDirective implements OnInit {

// Output that will emit outside the directive
@Output() updateProperty: EventEmitter<any> = new EventEmitter();

// When 'update' is called we emit the value
update(event){
  this.updateProperty.emit(this.el.nativeElement.innerText);
}

现在我们的指令正确发出,我们必须捕获组件中的值。 为简洁起见,仅提供模板

<div contentEditable="true" [myProperty]="name" (updateProperty)="name = $event"></div>

updateProperty 是指令中的@Output。当它被触发时,我们会捕获它并且我们发出的值将被分配给$event。之后,我们将$event 分配给我们的属性name,然后您的应用程序就可以运行了。

这是您的plnkr 工作。希望对你有帮助。

更新

感谢answer,我看到你要求的东西是可能的。

您可以将输出与语法 [()] 脱糖时调用的内容相匹配。如果你有类似[(myProperty)]="expr" 的语法,它会被取消为[myProperty]="expr" (myPropertyChange)="expr = $event"

所以把原来的答案改成如下

@Output() myPropertyChange: EventEmitter<any> = new EventEmitter();
update(event){
  this.myPropertyChange.emit(this.el.nativeElement.innerText);
}

它会给你这个模板,这是你从一开始就要求的。

<div contentEditable="true" [(myProperty)]="name"></div>

这是plnkr 更新为真正的正确答案。

【讨论】:

  • 感谢这个 Eric - 这很有帮助。这似乎是 Angular2 希望我们把事情联系起来的方式。我需要一点时间来适应。我不禁想到让我的组件直接处理它可能会更好,因为它是如此简单。
  • @MarkM 我更新了我的答案以反映您真正要求的内容。如果误导了您,我真的很抱歉。
  • 是的!这是一个更好的解决方案。感谢您的更新 - 我想我永远也想不通。
  • @EricMartinez 是什么触发了您最终答案中的更新功能?
【解决方案2】:

我发现这个非常流畅的解决方案适用于我的案例(向现有 UI 添加只读角色),它使用 @Host 装饰器注入您想要在指令中设置属性的组件。就我而言,我有一个具有只读属性的抽象类,然后由所有自定义组件扩展。

@Directive({
  selector: 'authCheck'
})
export class ComponentReadonlyDirective implements OnInit {

  constructor(private authService: AuthorizationService,
              @Host() private baseComponent: BaseComponent) {
  }

  ngOnInit() {
    if (!this.authorizationService.canEdit()) {
      this.baseComponent.readonly = true;
    }
  }
}

在选择器部分,我直接放置了实现 BaseComponent 的自定义组件的选择器(例如 my-comp)。这是因为我希望该指令自动应用于 my-comp 的所有实例。我有一个额外的参数可以关闭指令。

如果这是使用指令的单个组件 - 将其放在 BaseComponent 的位置。

如果多个组件将使用相同的指令 - 您需要通过在扩展类中指定提供程序来指定将在 @Host 参数上注入的内容:

@Component({
  selector: 'my-comp',
  ...
  providers: [{
      provide: BaseComponent, useExisting: forwardRef(() => MyComp)
  }]
})
export class MyComp extends BaseComponent { ... }

来源:https://github.com/angular/angular/issues/13776

【讨论】:

    【解决方案3】:

    如果您只是想使用纯 JavaScript 更改 并且 想使用 [(model] ) 路线,那么这是给你的。

    const input = this.el.nativeElement.querySelector('#myElement');
    input.value = 'My Programmatic Value';
    input.dispatchEvent(new Event('input'));
    

    问题 - https://github.com/text-mask/text-mask/issues/696

    解决方案 - https://github.com/text-mask/text-mask/issues/696#issuecomment-354887412

    希望这对某人有所帮助。

    干杯!

    【讨论】:

      猜你喜欢
      • 2016-07-27
      • 1970-01-01
      • 1970-01-01
      • 2017-11-27
      • 2016-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多