在运行时分配Angular结构指令

时间:2018-04-22 07:10:57

标签: javascript angular angular2-directives

我试图在运行时将角度代码中的* ngIf指令分配给模板。无法找到办法。 view / templateref是一个选项吗?或者有一个不同的方式和一个更容易的方式。首先有可能吗?

更新

代码有点凌乱和混乱,所以避免它。但是这里是DOM代码的大致外观以及为什么我需要动态添加内置结构指令。

<div>
  <input type="text" [value]="userProvidedValue">
  <textarea [value]="someDynamicDOMCodefromWYSIWYG">
    <!-- user provided provided code or dynamic code -->
  </textarea>
</div>
<div>
  <select *ngIf="fetchArraywithHttpFromuserProvidedValue">
    <option *ngFor="let val of fetchArraywithHttpFrom-userProvidedValue" value=""></option>
  </select>
</div>
<div>
  <ng-template>
    <!-- Some User provided code or dynamic code which might need to use *ngIf OR *ngFor -->
    <!-- The *ngIf OR *ngFor will be added dynamically based on a manipulator function which is decided from the value of fetchArraywithHttpFromuserProvidedValue -->
  </ng-template>
</div>

更新

我正在根据userProvidedValue值执行获取请求,并且获取请求的结果决定fetchArraywithHttpFromuserProvidedValue数组。其次,基于从获取请求派生的fetchArraywithHttpFromuserProvidedValue的值,决定是否在切换选项中显示用户提供的模板或预定的模板集。 (只有部分用户提供的模板需要* ngIf指令。用户模板在JS中解析以获取所需的部分)。该用例类似于创建从用户获取结构的HTML设计/页面的工具。这正是一个类似的工具,只是因为我没有创建一个创建用户定义的HTML页面的工具。

请帮我解决这个问题。如果这是不可能的,那么请推荐一个替代方案,允许我类似地分配功能或在这种情况下让我解决方法。

更新2

如下面的一个答案中指出的那样,以下所有模板都无法使用elementref或使用ViewContainerRef + TemplateRef进行正确的解析/编译:

<input [value]="someVariableFromClass"/>

<input value="{{someVariableFromClass}}"/>

<div *ngFor="let item of items">{{item}}</div>

以下是有效的,如果在构建和加载应用程序之前模板位于DOM中(不是动态添加):

<ng-template #tpl>
  <!-- Add the template to #vcr using ViewContainerRef from the class -->
    <div *ngFor="let item of items">{{item}}</div>
</ng-template>
<div #vcr>
    <!-- Add the template from #tpl using ViewContainerRef from the class -->
</div>

目前,我正在尝试使用Angular中的编译器API,并检查compileModuleAndAllComponentsAsync<T>(moduleType: Type<T>): Promise<ModuleWithComponentFactories<T>>是否可以帮助我完成此用例。问题似乎是我将通过将html作为模板分配给组件来创建一个全新的组件,然后创建一个动态模块,然后在插入视图之前编译整个(逻辑我正在尝试当前 - 不工作然而)。在此之后(如果我成功),我将尝试使用指令添加组件模板,并查看是否编译正确。欢迎任何帮助。看起来我最终可能会通过向手工占位符添加静态指令并添加[innerHTML]= / safeHTML / Sanitize API,如果我没有成功的话。虽然不太理想。如果可以,请帮助替代方案。

我正在使用这个例子,虽然它的plunkr目前无法正常工作。

How can I use/create dynamic template to compile dynamic Component with Angular 2.0?

http://plnkr.co/edit/wh4VJG?p=preview

2 个答案:

答案 0 :(得分:2)

您不会在* ngIf中调用fetch方法。每当角度决定进行变化检测时,...... *ngIf="..."内部就会被执行,并且每秒可能会有几十次。您不希望为自己的后端部署DDOS。

这就是为什么你应该放置isUserProvidedValueValid这样的字段并在你的HttpClient调用的订阅中更新该字段的原因:

userProvidedValue: any;
isUserProvidedValueValid: boolean = false;

constructor(private httpClient: HttpClient) {}

doFetch() { // called by a button-click for example
    this.isUserProvidedValueValid = false;
    this.httpClient
      .get<any>(SOME_URL)
      .subscribe(res => {
          if (res) { // you might have a complex check here, not just not-undefined
               this.isUserProvidedValueValid = true;
          }
          // you might consider putting this in the if-clause and in the *ngIf only check for userProvidedValue being not null
          this.userProvidedValue = res;
      });
}

现在为您的用户提供的代码:首先,您需要清理它。您可以使用指令内的管道(您不需要使用ng-template,使用普通标签的innerHtml),例如:https://stackoverflow.com/a/39858064/4125622

  template: `<div [innerHtml]="html | safeHtml"></div>`,

或者在上面代码中的.subscribe()之前,你可以做到

// domSanitizer needs to be injected in constructor as well
.map(res => this.domSanitizer.bypassSecurityTrustHtml(res)); 

如果你需要转换这个代码,你可以添加另一个.map() - RXJS-mapper或另一个自定义管道 - 这取决于你喜欢哪种变换器。在变换器中,您可以使用VanillaJS来操纵用户代码。也许HTML-parser-plugin或JSON-toHTML-parser-plugin或类似的东西可能对你有用 - 取决于你的用户提供的数据类型。

答案 1 :(得分:-1)

不,你不能动态地添加结构指令,你需要通过思考你的应用程序在以后期待什么来接近它。

例如,如果您计划循环遍历一个数组,我猜这是您打算查看代码时所做的事情,您可以执行以下操作:

hotels: any;

<div *ngIf="hotels.length > 0">
  <div *ngFor="let item of hotels">{{item.name}}</div>
</div>