动态地将组件附加到Angular 5中的div

时间:2018-01-23 21:19:44

标签: angular typescript angular-directive angular5

我有这个

https://angular-dynamic-component-append.stackblitz.io/

我设法动态追加一个元素,但它没有被编译。 我看过许多教程,如this

但它并不是我真正需要的东西。通常他们使用标签符号来识别容器。

我需要将一个组件附加到可能有的任何元素上 我的自定义指令。

我还需要使用指令的绑定值来控制附加元素的[hidden]属性。

目标

  1. 覆盖现有组件的行为:
    • 添加要显示/隐藏的属性
    • 添加一个类以自定义外观
  2. 减少html编码
    • 无需编写整个组件<my-comp></mycomp>
    • 无需了解课程
    • 如果更改了类名,则自动执行
      1. 更改应用指令的元素
    • 最终目标是将一个类添加到contaner元素
  3. 预期来源

    <div [myDirective]="myBoolean">
        <p>some content</p>
    </div>
    

    预计已编译

    <div [myDirective]="myBoolean" class="myDirectiveClass1">
        <p>some content</p>
         <someComponent [hidden]="myBoolean" class="myDirectiveClass2"></someComponent>
    </div>
    

    有没有办法实现这个目标?

    提前谢谢

3 个答案:

答案 0 :(得分:2)

非常简单。我刚给你做了一个例子。

请阅读loader指令内的注释。

https://github.com/garapa/studying/tree/master/loader

编辑:

你的组成部分:

export class LoaderComponent {

  loading;

  constructor() { }

}

您的指示

export class LoaderDirective implements OnDestroy {

  private componentInstance: ComponentRef<LoaderComponent> = null;

  @Input()
  set appLoader(loading: boolean) {
    this.toggleLoader(loading);
  }

  constructor(
    private viewContainerRef: ViewContainerRef,
    private componentFactoryResolver: ComponentFactoryResolver
  ) { }

  toggleLoader(loading: boolean) {
    if (!this.componentInstance) {
      this.createLoaderComponent();
      this.makeComponentAChild();
    }

    this.componentInstance.instance.loading = loading;
  }

  private createLoaderComponent() {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(LoaderComponent);
    this.componentInstance = this.viewContainerRef.createComponent(componentFactory);
  }

  private makeComponentAChild(){
    const loaderComponentElement = this.componentInstance.location.nativeElement;
    const sibling: HTMLElement = loaderComponentElement.previousSibling;
    sibling.insertBefore(loaderComponentElement, sibling.firstChild);
  }

  ngOnDestroy(): void {
    if (this.componentInstance) {
      this.componentInstance.destroy();
    }
  }

}

你的模块

@NgModule({
  ...
  entryComponents: [
    LoaderComponent
  ]
})

答案 1 :(得分:1)

这是我开始工作的方式

import {
  Renderer2,
  Directive,
  Input,
  ElementRef,
  OnChanges,
  ViewEncapsulation
} from "@angular/core";
import { MatSpinner } from "@angular/material";

@Directive({
  selector: "[myDirective]"
})
export class MyDirective {

  @Input()
  set myDirective(newValue: boolean) {
    console.info("myDirectiveBind", newValue);
    if (!!this._$matCard) {
      const method = newValue ? "removeClass" : "addClass";
      this.renderer[method](this._$matCard, "ng-hide");
    }
    this._myDirective = newValue;
  }

  private _myDirective: boolean;
  private _$matCard;

  constructor(private targetEl: ElementRef, private renderer: Renderer2) {
    this._$matCard = this.renderer.createElement('mat-card');
    const matCardInner = this.renderer.createText('Dynamic card!');
    this.renderer.addClass(this._$matCard, "mat-card");
    this.renderer.appendChild(this._$matCard, matCardInner);
    const container = this.targetEl.nativeElement;
    this.renderer.appendChild(container, this._$matCard);
  }


}

import {
  Component,
  ElementRef,
  AfterViewInit,
  ViewEncapsulation
} from '@angular/core';

@Component({
  selector: 'card-overview-example',
  templateUrl: 'card-overview-example.html',
  styleUrls: ['card-overview-example.css']
})
export class CardOverviewExample {
  
  hideMyDirective = !1;

  constructor(private _elementRef: ElementRef) { }

  getElementRef() {
    return this._elementRef;
  }

  ngAfterViewInit() {
    let element = this._elementRef.nativeElement;
    let parent = element.parentNode;
    element.parentNode.className += " pippo";

  }
}
.ng-hide {
  display: none;
}
<mat-card>Simple card</mat-card>
<div class="text-center">
  <button (click)="hideMyDirective = !hideMyDirective">
    Toggle show dynamic card
</button>
</div>
<br />
<span>hideMyDirective: {{hideMyDirective}}</span>
<hr />
<div class="myDiv" [myDirective]="hideMyDirective">
    <ul>
      <li>My content</li>
      </ul>
</div>

答案 2 :(得分:0)

要在其中插入组件的组件html文件中:

import React, { Component } from 'react'
import Slider from 'react-rangeslider'
import Link from "next/link";
import axios from "axios";
import getConfig from "next/config";
const config = getConfig();

class Horizontal extends Component {
    constructor (props, context) {
        super(props, context)
        this.state = {
            apiUrl:config.publicRuntimeConfig.publicRuntimeConfigValue.apiUrl,
        }
    }
    handleChangeStart = () => {
        console.log('Change event started')
    };
    handleChange = value => {
        this.setState({
            value: value
        })};

    handleChangeComplete = () => {
        console.log('Change event completed')
    };
    saveValue = () => {
        console.log('saveValue ...', this.state);

        axios.post( this.state.apiUrl+'/api/v1/LeadSurvey/save', {
            'squareFeet':this.state.value,

        },  {}  )
    };

    render () {
        const { value } = this.state
        return (
            <div>

                <div className='slider'  style={{ marginTop:'165px',marginLeft:'319px',width:'700px',backgroundColor:'EF5350'}} >

                    <Slider min={850} max={5000} value={value} onChangeStart={this.handleChangeStart}
                        onChange={this.handleChange}
                        onChangeComplete={this.handleChangeComplete}
                    />
                    <div className='value'>{value} Squarefeet</div>
                    <div style={{marginTop:'86px'}}>
                        <Link prefetch href="/estimate"><a href="#" >


                            <span onChange={this.handleChange} onClick={() => this.saveValue()} >Next</span></a></Link>

                    </div>

                </div>
            </div>
        )
    }
}

export default Horizontal

要在其中插入组件的组件ts文件中:

'Component_to_insert'->是要插入另一个组件内部的组件。

<div #target>
</div>