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은 다음에서 찾을 수 있습니다. Angular2에서 ComponentResolver 및 ngFor를 사용하여 동적 anchorName / Components 생성
Dartdocs 사이트는 TypeScript 에도 적용 할 수있는 Angular 2 DynamicComponentLoader 클래스에 대한 멋진 문서를 제공합니다.
요컨대 :
사용할 템플릿으로 간단한 구성 요소
@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;
}
내 솔루션 :
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.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, []);
});
}
}
@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 }
]
});
"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']
})
보안 문제로 인해 Angular 2에서는 이러한 동적 템플릿 생성 방법을 사용할 수 없습니다. 안타깝게도 Angular 1에서 이전 응용 프로그램이 이러한 방식으로 동적으로 구동되었습니다.
For Angular 2 - This could be a differeny way of doing the same (link example below). By updating the template html files to be components in the application, then injecting them into (the place where you were trying to create the templateUrl with a string etc) view component template parameter as elements (using DynamicComponentLoader).
https://angular.io/docs/js/latest/api/core/DynamicComponentLoader-class.html
Hope, github example for you will help you! There are example to compile dynamic html. So, you can load HTML by any of your Service and then compile it.
1- install this library
npm i -D html-loader
============================================================
2- In webpack.config use html-loader for html files
{ test: /\.html$/, loaders: ['html-loader'] }
============================================================
3- If you use ionic , you can copy webpack.config.js from the path "node_modules/@ionic/app-scripts/config/webpack.config.js" then add the html loader to it
=============================================================
4-If you use ionic In package.json add these lines
"config": {
"ionic_bundler": "webpack",
"ionic_webpack": "webpack.config.ionic.js"
},
=============================================================
5-Then you can use it as below
@Component({
selector: 'page-login',
// templateUrl:"./login.html"
template: function(){
if(globalVariables.test==2) {
return require("./login2.html")
}
else
{
return require("./login.html")
}
}(),
})
======================================
6-If there is unresolved error with require function you can put it in declarations.d.ts file as the below :
declare var require: any;
참고URL : https://stackoverflow.com/questions/31692416/dynamic-template-urls-in-angular-2
'IT TIP' 카테고리의 다른 글
| mongodb에서 데이터 중복이 너무 많습니까? (0) | 2020.11.05 |
|---|---|
| CSS 픽셀이 분수 일 수 있습니까? (0) | 2020.11.05 |
| Linux 커널 모듈을 사용하는 것이 무엇인지 알아내는 방법이 있습니까? (0) | 2020.11.05 |
| Docker, Puppet 및 Vagrant를 사용하여 LAMP 웹 애플리케이션을 개발하는 방법은 무엇입니까? (0) | 2020.11.05 |
| 접미사 트리 및 시도. (0) | 2020.11.05 |