Angular 2 中的动态模板 URL

IT技术 javascript angular
2021-02-08 06:03:37

我一直在玩弄角2在过去的几天,不知道是否有可能提供一个动态templateUrl@View装饰。

我试过给它传递一个函数并从它返回一个字符串,但整个函数只是变成了一个字符串。

我之前也没有真正使用过 Angular 1.x,所以我不知道我是否只是以错误的方式来解决这个问题,但这是否可能,或者有没有更好的方法来创建动态视图?

例如,如果用户未登录,我可能想显示一个表单,但如果他们已登录,则显示一条文本消息。

像这样的东西不起作用:

@Component({
  selector: 'my-component'
})
@View({
  // This doesn't work
  templateUrl: function() {
    return this.isLoggedIn ? 'logged-in.html' : 'logged-out.html';
  }
})
class MyComponent {
  constructor() {
    this.loggedIn = false;
  }
}

任何帮助,将不胜感激。

6个回答

虽然可能不是最优雅的解决方案,但我使用 DynamicComponentLoader 和 ElementRef 为组件动态分配模板值。事实上,我一直在寻找一种解决方案,可以将多个自定义组件添加到占位符中。

我在 shmck 概述的函数中尝试了服务注入,这不起作用,因为在调用模板函数时服务尚不可用。确实,this指的是Window对象。

我使用的解决方案的参考 URL 可以在以下位置找到:create dynamic anchorName/Components with ComponentResolver 和 ngFor in Angular2

我也将这种方式称为 Plnkr1Plnkr2

Dartdocs站点提供了关于 Angular 2 DynamicComponentLoader 类的很好的文档,也适用于 TypeScript。

简而言之:

一个简单的组件作为要使用的模板

@Component({
  selector: 'dt2-simple-block',
  properties: ["idx"],
  template: `<h1>Simple block for  {{ idx }} </h1>`,
  directives: []
})
class dt2SimpleBlock {
  constructor() {
  }
}

包含要添加的所有组件的组件的构造函数(我的应用程序需要包含多个子组件:

 constructor(loader: DynamicComponentLoader, elementRef: ElementRef) {

  //iterate
  for (var i = 0; i < toSomething; i++) {
      // build the template
      var blockdirective = 'dt2-simple-block'
      var template = '<' + blockdirective + 
                     ' idx="' + this.userBlocks.userHomePanelBlocks[i] +
                     '"></' + blockdirective + '>';
      console.log(template);   // debugging purpose
      var directives = [dt2SimpleBlock];
        loader.loadNextToLocation(toComponent(template, directives), elementRef);
    }

并且将作为 util 放置在某处的辅助函数

function toComponent(template, directives = []) {
  @Component({ selector: 'fake-component' })
  @View({ template, directives })
  class FakeComponent { }

  return FakeComponent;
}
这是什么字面意思{template, directives}
2021-03-27 06:03:37
仅供参考DynamicComponentLoader已弃用。angular.io/docs/ts/latest/api/core/index/...
2021-03-31 06:03:37
@LS.Shanghai:这是 ES6/TypeScript 的简写{template: template, directives: directives}
2021-04-11 06:03:37

我的解决方案:

Angular 2.0 ViewResolver 类

class myViewResolver extends ViewResolver{
    resolve(component: Type): ViewMetadata {        
        var view =  super.resolve(component);
        // TODO: Write logic here:-)
        view.templateUrl = 'app/app.html';
        return view;
    }
}
bootstrap(App,[
    provide(ViewResolver , {useClass:myViewResolver})
]);
根据这个github.com/angular/angular/commit/0988cc8, ViewResolver 被合并到DirectiveResolver
2021-03-14 06:03:37
@Aboodz 知道现在DirectiveResolver已删除如何执行此操作吗?
2021-03-23 06:03:37
看起来相当简单!这适用于最新的 rc 版本吗?
2021-04-12 06:03:37

不完全是你所要求的,但值得一提的是:

另一个适用于大多数用例的简单解决方案是将逻辑放在模板本身中,如下所示:

@Component({
  selector: 'my-component'
})
@View({
// Note1: Here, I use template instead of templateUrl.
// Note2: I use ES6 string interpolation + require() to embed/load the other templates, but you can do it however you like.
  template: `
    <div [ngSwitch]="loggedIn">
      <template [ngSwitchCase]="true"> ${require('./logged-in.html')} </template>
      <template ngSwitchDefault> ${require('./logged-out.html')} </template>
    </div>`
})
class MyComponent {
  constructor() {
    this.loggedIn = false;
  }
}

此解决方案的缺点是您提供的 js 文件最终包含两个模板,因此这可能是大型模板的问题(但实际上只渲染一个模板,并且在许多情况下 js 大小开销是可以接受的)。

我的解决方案:(关于此的美妙之处在于 html 和 css 文件的延迟加载。)

这是 home.componenet.ts

import { Component } from '@angular/core';
import { DynamicHTMLOutlet } from './../../directives/dynamic-html-outlet/dynamicHtmlOutlet.directive';
import { TranslateService, LangChangeEvent } from 'ng2-translate/ng2-translate';

@Component({
  selector: 'lib-home',
  templateUrl: './app/content/home/home.component.html',
  directives: [DynamicHTMLOutlet]
})
export class HomeComponent {
  html_template = `./app/content/home/home_`;
  html: string;
  css: string;
  constructor(translate: TranslateService) {
        this.html = this.html_template + translate.currentLang;
        this.css = './app/content/home/home.component.css';
    translate.onLangChange.subscribe((event: LangChangeEvent) => {
          this.html = this.html_template + translate.currentLang;
          this.css = './app/content/home/home.component.css';
    });
  }

 }

我使用的指令并做了一些更改:这是在 home.componenet.html

<dynamic-html-outlet [htmlPath]="html" [cssPath]="css"></dynamic-html-outlet>

这是动态组件的指令:

import {
  Component,
  Directive,
  ComponentFactory,
  ComponentMetadata,
  ComponentResolver,
  Input,
  ReflectiveInjector,
  ViewContainerRef,

} from '@angular/core';
import { TranslatePipe } from 'ng2-translate/ng2-translate';
declare var $:any;

export function createComponentFactory(resolver: ComponentResolver, metadata: ComponentMetadata): Promise<ComponentFactory<any>> {
    const cmpClass = class DynamicComponent {};
    const decoratedCmp = Component(metadata)(cmpClass);
    return resolver.resolveComponent(decoratedCmp);
}

@Directive({
    selector: 'dynamic-html-outlet',
})
export class DynamicHTMLOutlet {
  @Input() htmlPath: string;
  @Input() cssPath: string;

  constructor(private vcRef: ViewContainerRef, private resolver: ComponentResolver) {
  }

  ngOnChanges() {
    if (!this.htmlPath) return;
    $('dynamic-html') && $('dynamic-html').remove();
    const metadata = new ComponentMetadata({
        selector: 'dynamic-html',
        templateUrl: this.htmlPath +'.html',
        styleUrls:  [this.cssPath],
        pipes: [TranslatePipe]
    });
    createComponentFactory(this.resolver, metadata)
      .then(factory => {
        const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
        this.vcRef.createComponent(factory, 0, injector, []);
      });
  }
}
ComponentMetadata 和 ComponentResolver 在 2.0 Angular 核心中似乎不再可用:(
2021-04-03 06:03:37
我们现在如何使用 angular 2.0 做到这一点?:(
2021-04-06 06:03:37

使用 aot "ng serve --aot" 编译您的应用程序。

export let DEFAULT_PREFIX :string= './app.component';
//or localStorage.getItem('theme')
export function getMySuperTemplate(template: string) {
  return DEFAULT_PREFIX + template + '.html';
}

@Component({
  selector: 'app-root',
  templateUrl: getMySuperTemplate('2'),
  styleUrls:['./app.component.css']
})
'2'这里硬编码的意义何在?它不会打败OP问题的重点吗?例如,如果我有一个返回的服务,那么我'2'如何能够调用该方法(从组件类)?
2021-03-16 06:03:37