2016-04-20 3 views
2

Я пытаюсь получить доступ к элементу DOM за пределами элемента текущей директивы .. для поведения, подобного изменению размера, используя внешний элемент в качестве дескриптора и не изменять целевую разметку, что очень важно, особенно не используя переключение, как <ng-content>.
Что я делаю сейчас является то, что я думаю, что немного неортодоксальные, как с помощью BrowserDomAdapter: angular2: управлять элементом снаружи директивы

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... 
} 

И шаблон выглядит следующим образом:

<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

В чем проблема с '' в вашем случае? –

ответ

1

Вы можете использовать переменные шаблона :

@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

Ни в коем случае, я не хочу напрямую использовать 'document'. Я использую «BrowserDomAdapter», потому что, может быть, в какой-то момент я, например, буду использовать другой тип браузера или что-то совершенно другое ... но я думаю, что даже это ненадежно для переносимости. Я думал об использовании какой-то другой парадигмы внутри рамки ... Я не знаю .. – Billy

2

Я бы использовал директиву, которая применяется к целевому элементу, который выполняет фактическую манипуляцию непосредственно с целью.

Затем вы можете ввести его с помощью конструктора. Это всегда вводит от ближайшего родителя, где он находит эту директиву.

@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

kemsky Спасибо!

на основе вашего предложения относительно переменных шаблона я придумал это решение:

@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

Также благодаря Günter Zöchbauer. Я построил другое решение, используя родительскую директиву; это потому, что дескриптор и цель на самом деле не были в одном и том же дереве, поэтому мне нужен «корень» для общения.

@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

Смежные вопросы