2016-04-20 15 views
2

Ich versuche auf ein DOM-Element außerhalb der aktuellen Direktive Element .. für eine Größe anpassen-ähnliches Verhalten, mit einem externen Element als ein Handle und die Zielmarkierung nicht so viel zu ändern, besonders nicht mit der Transclusion wie <ng-content>.
Was ich jetzt tun, ist etwas denke ich, ein bisschen unorthodox, wie mit der BrowserDomAdapter: angular2: manipulieren Element außerhalb der Direktive

import {Directive, Input, HostListener} from 'angular2/core'; 
import {BrowserDomAdapter} from 'angular2/platform/browser'; 

@Directive 
({ 
    selector: '[resizable-handle]', 
    providers: [BrowserDomAdapter] 
}) 
export class ResizableHandle 
{ 
    // get selector from actual directive selector attribute 
    @Input('resizable-handle') resizableSelector: string; 

    constructor(private _domAdapter: BrowserDomAdapter){} 

    @HostListener('mousedown', ['$event']) 
    startResize(e: MouseEvent) 
    { 
    this._domAdapter.query(this.resizableSelector); //... manipulate this native element 
    } 
    //... and so on... 
} 

Und die Vorlage sieht wie folgt aus:

<a [resizable-handle]="'.target-container'"> ... </a> 
<!-- ...somewhere further, on a different level, the target I don't want to touch in order to get this working... --> 
<div class="target-container"> ... </div> 
+0

Was ist das Problem mit '' in Ihrem Fall? –

Antwort

1

Sie Template-Variablen verwenden könnte :

@Input('resizable-handle') resizableSelector: ElementRef; 

<a [resizable-handle]="target-container"> ... </a> 
<!-- ...somewhere further, on a different level, the target I don't want to touch in order to get this working... --> 
<div #target-container> ... </div> 
+0

Nein, ich möchte das 'Dokument' nicht direkt verwenden. Ich benutze den 'BrowserDomAdapter', weil ich vielleicht zum Beispiel einen anderen Browsertyp oder etwas ganz anderes verwenden werde ... aber ich denke, auch das ist unzuverlässig für die Portabilität. Ich dachte daran, ein anderes Paradigma im Framework zu verwenden ... Ich weiß es nicht .. – Billy

2

Ich würde eine Anweisung verwenden, die auf das Zielelement angewendet wird, das die tatsächliche Manipulation direkt auf dem Ziel ausführt.

Dann können Sie es mit dem Konstruktor injizieren. Dies spritzt immer vom nächsten Elternteil, wo es diese Direktive findet.

@Directive({ 
    selector: '[resizable-target]', 
    host: {'[style.border]': 'border'}, 
}) 
export class ResizableTarget { 
    // change style just to demonstrate this directive can be manipulated 
    border:string = "solid 3px blue"; 

    @HostBinding('class.reached') reached:boolean = false; 
} 
@Directive({ 
    selector: '[resizable-handle]', 
}) 
export class ResizableHandle { 
    // inject the target 
    constructor(private _target:ResizableTarget) {} 

    @HostListener('mousedown', ['$event']) 
    startResize(e: MouseEvent) { 
    // call methods or set properties in order to manipulate the target 
    this._target.reached = true; 
    this._target.border = "solid 3px red"; 
    } 
} 
@Component({ 
    selector: 'my-app', 
    directives: [ResizableTarget, ResizableHandle], 
    template: ` 
    <h1>Hello</h1> 

    <div resizable-target> 
     <div> 
     <div> some content 
      <div resizable-handle>handle</div> 
     </div> 
     </div> 
    </div> 
    `, 
}) 
export class AppComponent { 
} 

Plunker example

3

Dank kemsky!

Basierend auf Ihren Vorschlag zur Template-Variablen Ich habe diese Lösung ausgedacht:

@Directive 
({ 
    selector: '[resizable-handle]', 
    host: { '(click)': 'emitHeight()' } 
}) 
export class ResizableHandle 
{ 
    @Input('resizable-handle') resizableSelector: ElementRef; 

    @Input() targetHeight: any; 
    @Output() targetHeightChange = new EventEmitter<number>(); 

    emitHeight(){ this.targetHeightChange.emit(100) } 
} 

@Component 
({ 
    selector: 'my-app', 
    directives: [ResizableHandle], 
    template: ` 
    <h1>Hello</h1> 
    <a [resizable-handle]="targetContainer" [(targetHeight)]="containerHeight" href="javascript:void(0)"> [click me!] </a> 
    <div #targetContainer [style.height.px]="containerHeight"> ... </div> 
    ` 
}) 
export class AppComponent 
{ 
    public containerHeight = 25; 
} 

Plunker preview

Auch dank Günter Zöchbauer. Ich habe eine andere Lösung mit einer Eltern-Direktive erstellt; Dies, weil der Handle und das Ziel tatsächlich nicht im selben Baum waren, also brauchte ich eine "Wurzel", um zu kommunizieren.

@Directive({ selector: '[resizable-handle]' }) 
export class ResizableHandle 
{ 
    constructor(@Host() @Inject(forwardRef(()=>Resizable)) private _resizable: Resizable){} 
    // simulate dropping a resize handle here 
    @HostListener('click', ['$event']) 
    emitHeight(){ this._resizable.change = Math.max(Math.random()*100, 25); } 
} 

@Directive({ selector: '[resizable-target]' }) 
export class ResizableTarget 
{ 
    constructor(@Host() @Inject(forwardRef(()=>Resizable)) private _resizable: Resizable) 
    { 
    this._resizable.change.subscribe(c => this.height = c); 
    } 

    @HostBinding('style.height.px') public height; 
} 

@Directive({ selector: '[resizable]' }) 
export class Resizable 
{ 
    private _change: number; 
    private _observableChange: Observable<number>; 

    constructor() 
    { 
    this._observableChange = Observable.create(observer => this._change = observer).share(); 
    } 
    set change(value){ this._change.next(value) } 
    get change(){ return this._observableChange; } 
} 

@Component 
({ 
    selector: 'my-app', 
    directives: [ResizableHandle, ResizableTarget, Resizable], 
    template: ` 
     <div resizable> 
     <a resizable-handle href="javascript:void(0)"> [click me!] </a> 
     <p>...</p> 
     <div resizable-target> ...a... </div> 
     <div resizable-target> ...b... </div> 
     </div> 
    `, 
}) 
export class AppComponent{} 

Plunker preview

Verwandte Themen