programing

Angular 2의 동적 템플릿 URL

magicmemo 2023. 7. 25. 20:51
반응형

Angular 2의 동적 템플릿 URL

나는 지난 며칠 동안 Angular 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;
  }
}

어떤 도움이라도 주시면 감사하겠습니다.

가장 우아한 솔루션은 아니지만 DynamicComponentLoader 및 ElementRef를 사용하여 구성 요소에 템플릿 값을 동적으로 할당했습니다.사실 저는 여러 사용자 정의 구성요소를 플레이스홀더에 추가할 수 있는 솔루션을 찾고 있었습니다.

shmck에서 설명한 기능으로 서비스 인젝션을 시도해 보았습니다. 템플릿 기능이 호출되었을 때 아직 서비스를 이용할 수 없기 때문에 이것은 작동하지 않습니다.실제로.thisWindow 개체를 나타냅니다.

내가 사용한 솔루션에 대한 참조 URL은 다음에서 찾을 수 있습니다: ComponentResolver Angular2에서 ngFor를 사용하여 동적 anchorName/Components 만들기

저는 또한 이 방법Plnkr1과 Plnkr2로 참조합니다.

Dartdocs 사이트는 TypeScript에도 적용 가능한 Angular 2 Dynamic ComponentLoader 클래스에 대한 훌륭한 문서를 제공합니다.

간단히 말해서:

사용할 템플릿으로서의 단순 구성요소

@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);
    }

그리고 도우미 기능은 유용하게 쓰일 것입니다.

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

  return FakeComponent;
}

내 솔루션:

Angular 2.0 뷰 해상도 클래스

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})
]);

요청하신 내용은 아니지만, 다음과 같이 언급할 가치가 있습니다.

대부분의 사용 사례에서 작동하는 또 다른 간단한 솔루션은 다음과 같이 논리를 템플릿 자체에 넣는 것입니다.

@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.componet.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.componnet.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, []);
      });
  }
}

"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']
})

@Eyal Vardi의 답변으로 업데이트 (ViewResolver사용되지 않음):

import { Directive, Type, Component } from '@angular/core';
import { DirectiveResolver } from '@angular/compiler';

class myViewUrlResolver extends DirectiveResolver {
    resolve(type: Type<any>, throwIfNotFound?: boolean): Directive {        
        let view = <any>super.resolve(type, throwIfNotFound);
        if (typeof view["templateUrl"] !== "undefined") {
            console.log("Yay!");
            let originalUrl = (<Component>view).templateUrl;
            (<Component> view).templateUrl = environment.nativeScriptAppPrePathPrefix + originalUrl.replace(".html", ".tns.html");
        }
        if (typeof view["styleUrls"] !== "undefined") {
            console.log("Yay2!");
            let originalUrls = (<Component>view).styleUrls;
            originalUrls.forEach((originalUrl, at) => (<Component>view).styleUrls[at] = environment.nativeScriptAppPrePathPrefix + originalUrl.replace(".html", ".tns.css"));
        }
        return view;
    }
}

platformNativeScriptDynamic().bootstrapModule(AppModule,{ 
  providers: [
    { provide: DirectiveResolver, useClass: myViewUrlResolver } 
  ]
});

보안 문제로 인해 Angular 2에서는 동적 템플릿을 만드는 이 방법을 사용할 수 없습니다.안타깝게도 Angular 1에서 이전 애플리케이션이 동적으로 이러한 방식으로 구동되었습니다.

각도 2의 경우 - 동일한 작업을 수행하는 다른 방법일 수 있습니다(아래 링크 예제).템플릿 html 파일을 응용프로그램의 구성요소로 업데이트한 다음 (문자열을 사용하여 templateUrl을 만들려는 위치 등)에 주입하면 구성요소 템플릿 매개변수를 요소로 볼 수 있습니다(DynamicComponentLoader 사용).

https://angular.io/docs/js/latest/api/core/DynamicComponentLoader-class.html

호프, 당신을 위한 허브 예시가 당신을 도울 것입니다!동적 html을 컴파일하는 예가 있습니다.따라서 서비스별로 HTML을 로드한 다음 컴파일할 수 있습니다.

1- 이 라이브러리 설치

npm i-D html 로더

============================================================

2 - webpack.config에서 html 파일에 html-loader 사용

 { test: /\.html$/,  loaders: ['html-loader']   }

============================================================

3- ionic을 사용하는 경우 "node_modules/@ionic/app-scripts/config/webpack.config.js" 경로에서 webpack.config.js를 복사한 다음 html 로더를 추가할 수 있습니다.

=============================================================

4-아이오닉 인 패키지를 사용하는 경우.json 이 줄들을 추가합니다.

"config": { 
    "ionic_bundler": "webpack",
    "ionic_webpack": "webpack.config.ionic.js" 
  },

=============================================================

5-그러면 아래와 같이 사용할 수 있습니다.

@Component({
  selector: 'page-login',
 // templateUrl:"./login.html"

   template:     function(){
    if(globalVariables.test==2) {

      return require("./login2.html")
    }
    else
    {
      return require("./login.html")
    }
  }(),
})

======================================

6-require 함수와 함께 해결되지 않은 오류가 있는 경우 아래와 같이 declarations.d.ts 파일에 넣을 수 있습니다.

var require 선언: any;

기술적인 에, 요소를 구성 수 .templateUrl다음을 사용합니다.*ngIf올바른 템플릿을 로드하기 위해 상위 구성 요소에 있습니다.

템플릿 1을 사용하는 구성 요소:

@Component({
  selector: 'template-one-component',
  templateUrl: './template-one.html'
})
export class TemplateOneComponent {
  title = 'This component uses one template';
}

템플릿 2를 사용하는 구성 요소:

@Component({
  selector: 'template-two-component',
  templateUrl: './template-two.html'
})
export class TemplateTwoComponent extends TemplateOneComponent {
}

상위 구성 요소:

@Component({
  selector: 'parent-component',
  template: `
    <template-one-component *ngIf="useTemplateOne; else useTemplateTwo"></template-one-component>

    <ng-template #useTemplateTwo>
      <template-two-component></template-two-component>
    <ng-template>
  `
})
export class ParentComponent {
  useTemplateOne: boolean;
}

언급URL : https://stackoverflow.com/questions/31692416/dynamic-template-urls-in-angular-2

반응형