मैं एक घटक टेम्पलेट में एक तत्व का चयन कैसे कर सकता हूं?


516

क्या किसी को पता है कि एक घटक टेम्पलेट में परिभाषित तत्व को कैसे पकड़ना है? पॉलिमर यह वास्तव में साथ आसान बना देता है $और $$

मैं बस सोच रहा था कि इसके बारे में कोणीय में कैसे जाया जाए।

ट्यूटोरियल से उदाहरण लें:

import {Component} from '@angular/core';

@Component({
    selector:'display',
    template:`
     <input #myname (input)="updateName(myname.value)"/>
     <p>My name : {{myName}}</p>
     `   
})
export class DisplayComponent {
    myName: string = "Aman";
    updateName(input: String) {
        this.myName = input;
    }
}

मैं कक्षा की परिभाषा के भीतर से कैसे पकड़ pया inputतत्व का संदर्भ प्राप्त कर सकता हूं ?

जवाबों:


936

इंजेक्शन लगाने ElementRefऔर उपयोग करने querySelectorया वहां से समान के बजाय, सीधे देखने के तत्वों को एक्सेस करने के बजाय एक घोषणात्मक तरीके का उपयोग किया जा सकता है:

<input #myname>
@ViewChild('myname') input; 

तत्त्व

ngAfterViewInit() {
  console.log(this.input.nativeElement.value);
}

StackBlitz उदाहरण

  • @ViewChild () पैरामीटर के रूप में निर्देश या घटक प्रकार, या टेम्पलेट चर के नाम (स्ट्रिंग) का समर्थन करता है।
  • @ViewChildren () अल्पविराम से अलग की गई सूची (वर्तमान में कोई रिक्त स्थान की अनुमति नहीं @ViewChildren('var1,var2,var3')) के रूप में नामों की सूची का समर्थन करता है ।
  • @ContentChild () और @ContentChildren () प्रकाश DOM ( <ng-content>प्रोजेक्ट तत्वों) में भी ऐसा ही करते हैं ।

वंशज

@ContentChildren() केवल वही है जो वंशजों के लिए क्वेरी करने की अनुमति देता है

@ContentChildren(SomeTypeOrVarName, {descendants: true}) someField; 

{descendants: true}डिफ़ॉल्ट होना चाहिए लेकिन 2.0.0 फाइनल में नहीं है और इसे बग माना जाता है।
यह 2.0.1 में तय किया गया था

पढ़ना

यदि कोई घटक और निर्देश हैं तो readपैरामीटर निर्दिष्ट करने की अनुमति देता है कि किस उदाहरण को वापस किया जाना चाहिए।

उदाहरण के लिए ViewContainerRefडिफ़ॉल्ट के बजाय गतिशील रूप से बनाए गए घटकों द्वारा आवश्यक हैElementRef

@ViewChild('myname', { read: ViewContainerRef }) target;

परिवर्तन की सदस्यता लें

भले ही बच्चों को केवल ngAfterViewInit()कॉल करते समय सेट किया जाता है और सामग्री बच्चों को केवल तब सेट किया ngAfterContentInit()जाता है जब उन्हें कॉल किया जाता है, यदि आप क्वेरी परिणाम के परिवर्तनों की सदस्यता लेना चाहते हैं, तो इसे अंदर किया जाना चाहिएngOnInit()

https://github.com/angular/angular/issues/9689#issuecomment-229247134

@ViewChildren(SomeType) viewChildren;
@ContentChildren(SomeType) contentChildren;

ngOnInit() {
  this.viewChildren.changes.subscribe(changes => console.log(changes));
  this.contentChildren.changes.subscribe(changes => console.log(changes));
}

सीधे डोम का उपयोग

केवल DOM तत्वों को क्वेरी कर सकते हैं, लेकिन घटक या निर्देश उदाहरण नहीं:

export class MyComponent {
  constructor(private elRef:ElementRef) {}
  ngAfterViewInit() {
    var div = this.elRef.nativeElement.querySelector('div');
    console.log(div);
  }

  // for transcluded content
  ngAfterContentInit() {
    var div = this.elRef.nativeElement.querySelector('div');
    console.log(div);
  }
}

मनमाना अनुमानित सामग्री प्राप्त करें

एक्सेस ट्रांसकोड की गई सामग्री देखें


12
एंगलियर टीमों ने एलीमेंटरीफ का उपयोग करने के खिलाफ सलाह दी, यह बेहतर समाधान है।
माननीय चाउ

7
वास्तव में inputयह भी एक है ElementRef, लेकिन आपको उस तत्व का संदर्भ मिलता है जिसे आप वास्तव में चाहते हैं, बजाय इसे होस्ट से क्वेरी किए ElementRef
गुंटर Zöchbauer

32
वास्तव में उपयोग ElementRefकरना ठीक है। इसके ElementRef.nativeElementसाथ उपयोग करना Rendererभी ठीक है। जो हतोत्साहित किया जाता है वह ElementRef.nativeElement.xxxसीधे संपत्तियों तक पहुंच रहा है ।
गुंटर ज़ोचाउर

2
@Natanael मुझे नहीं पता कि यह कहाँ या कहाँ से स्पष्ट रूप से प्रलेखित है, लेकिन यह नियमित रूप से मुद्दों या अन्य चर्चाओं में भी उल्लेख किया जाता है (कोणीय टीम के सदस्यों से) कि प्रत्यक्ष DOM की पहुँच से बचा जाना चाहिए। डोम सीधे एक्सेस करना (जो क्या गुण और के तरीकों तक पहुँचने है ElementRef.nativeElement)अगर यह भी आगामी ऑफ़लाइन टेम्पलेट संकलक टूट जाता है, तो आप Angulars सर्वर साइड प्रतिपादन और WebWorker सुविधा का उपयोग करने से रोकता है (मैं नहीं जानता कि - लेकिन मुझे नहीं लगता है कि)।
गुंटर Zöchbauer

10
जैसा कि रीड सेक्शन में ऊपर बताया गया है , यदि आप ViewChild के साथ एक तत्व के लिए नेटिवमेंट प्राप्त करना चाहते हैं, तो आपको निम्नलिखित कार्य करने होंगे: @ViewChild('myObj', { read: ElementRef }) myObj: ElementRef;
jsgoupil

203

आप ElementRefइसे अपने घटक के निर्माता में इंजेक्ट करके DOM तत्व के लिए एक हैंडल प्राप्त कर सकते हैं :

constructor(myElement: ElementRef) { ... }

डॉक्स: https://angular.io/docs/ts/latest/api/core/index/ElementRef-class.html


1
क्या आप अपना जवाब अपडेट कर सकते हैं? मैं एक मौजूदा समाधान देखना चाहता हूं क्योंकि ElementRefवह चला गया है।
जेफटॉपिया

23
ElementRefउपलब्ध है (फिर से?)।
गुंटर ज़ोचबॉयर

10
लिंक इस API का उपयोग अंतिम उपाय के रूप में करें जब DOM तक सीधी पहुँच आवश्यक हो। इसके बजाय कोणीय द्वारा प्रदान किए गए टेम्प्लेटिंग और डेटा-बाइंडिंग का उपयोग करें वैकल्पिक रूप से आप रेंडरर पर एक नज़र डालते हैं जो एपीआई प्रदान करता है जिसका उपयोग तब भी किया जा सकता है जब मूल तत्वों तक सीधी पहुंच का समर्थन नहीं किया जाता है। डायरेक्ट डोम एक्सेस पर भरोसा करने से आपके एप्लिकेशन और रेंडरिंग लेयर्स के बीच टाइट कपलिंग का निर्माण होता है जिससे दोनों को अलग करना और आपके एप्लिकेशन को वेब वर्कर में तैनात करना असंभव हो जाएगा।
संदीप तालबाथुला

@sandeeptalabathula तीसरे पक्ष के पुस्तकालय से फ़्लोटिंग डेट पिकर घटक संलग्न करने के लिए एक तत्व खोजने के लिए एक बेहतर विकल्प क्या है? मुझे पता है कि यह मूल प्रश्न नहीं था, लेकिन आप यह जानते हैं कि DOM में तत्वों को ढूंढना सभी स्थितियों में बुरा है ...
John

13
@ जॉन आह .. ठीक है। आप इसे आज़मा सकते हैं - this.element.nativeElement.querySelector('#someElementId')और इस तरह से कंस्ट्रक्टर को एलिमेंटरीफ पास करें .. private element: ElementRef, इम्पोर्ट लिब ...import { ElementRef } from '@angular/core';
sandeep talabathula

52
import { Component, ElementRef, OnInit } from '@angular/core';

@Component({
  selector:'display',
  template:`
   <input (input)="updateName($event.target.value)">
   <p> My name : {{ myName }}</p>
  `
})
class DisplayComponent implements OnInit {
  constructor(public element: ElementRef) {
    this.element.nativeElement // <- your direct element reference 
  }
  ngOnInit() {
    var el = this.element.nativeElement;
    console.log(el);
  }
  updateName(value) {
    // ...
  }
}

उदाहरण नवीनतम संस्करण के साथ काम करने के लिए अद्यतन किया गया

देशी तत्व के बारे में अधिक जानकारी के लिए, यहाँ


20

कोणीय 4+ : renderer.selectRootElementतत्व तक पहुंचने के लिए CSS चयनकर्ता के साथ प्रयोग करें ।

मुझे एक फॉर्म मिला है जो शुरू में एक ईमेल इनपुट प्रदर्शित करता है। ईमेल दर्ज किए जाने के बाद, प्रपत्र को उनके प्रोजेक्ट से संबंधित जानकारी जोड़ने के लिए उन्हें जारी रखने की अनुमति देने के लिए विस्तारित किया जाएगा। हालांकि, यदि वे एक मौजूदा ग्राहक नहीं हैं , तो फॉर्म में प्रोजेक्ट जानकारी अनुभाग के ऊपर एक पता अनुभाग शामिल होगा।

अब तक, डेटा प्रविष्टि भाग को घटकों में विभाजित नहीं किया गया है, इसलिए अनुभाग * ngIf निर्देशों के साथ प्रबंधित किए जाते हैं। मुझे प्रोजेक्ट नोट फ़ील्ड पर ध्यान केंद्रित करने की आवश्यकता है यदि वे एक मौजूदा ग्राहक हैं, या पहला नाम फ़ील्ड यदि वे नए हैं।

मैंने बिना किसी सफलता के समाधान की कोशिश की। हालाँकि, इस उत्तर में अपडेट 3 ने मुझे अंततः समाधान का आधा हिस्सा दिया। अन्य आधे इस धागे में MatteoNY की प्रतिक्रिया से आए । परिणाम यह है:

import { NgZone, Renderer } from '@angular/core';

constructor(private ngZone: NgZone, private renderer: Renderer) {}

setFocus(selector: string): void {
    this.ngZone.runOutsideAngular(() => {
        setTimeout(() => {
            this.renderer.selectRootElement(selector).focus();
        }, 0);
    });
}

submitEmail(email: string): void {
    // Verify existence of customer
    ...
    if (this.newCustomer) {
        this.setFocus('#firstname');
    } else {
        this.setFocus('#description');
    }
}

चूंकि केवल एक चीज जो मैं कर रहा हूं वह एक तत्व पर ध्यान केंद्रित कर रहा है, मुझे परिवर्तन का पता लगाने के साथ खुद को चिंता करने की आवश्यकता नहीं है, इसलिए मैं वास्तव renderer.selectRootElementमें कोणीय के बाहर कॉल चला सकता हूं । क्योंकि मुझे नए अनुभागों को प्रस्तुत करने के लिए समय देने की आवश्यकता है, तत्व चयन का प्रयास करने से पहले रेंडरिंग थ्रेड्स को पकड़ने की अनुमति देने के लिए तत्व अनुभाग को समय-समय पर लपेटा जाता है। एक बार जो सब सेटअप हो जाता है, मैं बस मूल सीएसएस चयनकर्ताओं का उपयोग करके तत्व को कॉल कर सकता हूं।

मुझे पता है कि यह उदाहरण मुख्य रूप से फ़ोकस इवेंट से संबंधित है, लेकिन मेरे लिए यह कठिन है कि इसका उपयोग अन्य संदर्भों में नहीं किया जा सकता है।


कक्षा Renderer को Angular 4.3.0 के बाद से DEPRECated किया जाता है। angular.io/api/core/Renderer
जेमी

15

*ngIfया के अंदर घटक उदाहरण को हथियाने की कोशिश कर रहे लोगों के लिए *ngSwitchCase, आप इस चाल का अनुसरण कर सकते हैं।

एक initनिर्देश बनाएँ ।

import {
    Directive,
    EventEmitter,
    Output,
    OnInit,
    ElementRef
} from '@angular/core';

@Directive({
    selector: '[init]'
})
export class InitDirective implements OnInit {
    constructor(private ref: ElementRef) {}

    @Output() init: EventEmitter<ElementRef> = new EventEmitter<ElementRef>();

    ngOnInit() {
        this.init.emit(this.ref);
    }
}

अपने घटक को किसी नाम के साथ निर्यात करें जैसे कि myComponent

@Component({
    selector: 'wm-my-component',
    templateUrl: 'my-component.component.html',
    styleUrls: ['my-component.component.css'],
    exportAs: 'myComponent'
})
export class MyComponent { ... }

प्राप्त करने के लिए इस टेम्पलेट का उपयोग ElementRefऔर MyComponentउदाहरण

<div [ngSwitch]="type">
    <wm-my-component
           #myComponent="myComponent"
           *ngSwitchCase="Type.MyType"
           (init)="init($event, myComponent)">
    </wm-my-component>
</div>

इस कोड का उपयोग टाइपस्क्रिप्ट में करें

init(myComponentRef: ElementRef, myComponent: MyComponent) {
}

12

ViewChildडेकोरेटर से आयात करें @angular/core, जैसे:

HTML कोड:

<form #f="ngForm"> 
  ... 
  ... 
</form>

टीएस कोड:

import { ViewChild } from '@angular/core';

class TemplateFormComponent {

  @ViewChild('f') myForm: any;
    .
    .
    .
}

अब आप कक्षा में किसी भी तत्व को एक्सेस करने के लिए 'myForm' ऑब्जेक्ट का उपयोग कर सकते हैं।

Source


लेकिन आपको ध्यान देना चाहिए कि आपको घटक वर्ग में टेम्पलेट तत्वों तक पहुंचने की आवश्यकता नहीं है, आपको केवल कोणीय तर्क को अच्छी तरह से समझने की आवश्यकता है।
हनी

3
किसी भी प्रकार का उपयोग न करें, टाइप करें तत्व है
जोहान्स

10
 */
import {Component,ViewChild} from '@angular/core' /*Import View Child*/

@Component({
    selector:'display'
    template:`

     <input #myname (input) = "updateName(myname.value)"/>
     <p> My name : {{myName}}</p>

    `
})
export class DisplayComponent{
  @ViewChild('myname')inputTxt:ElementRef; /*create a view child*/

   myName: string;

    updateName: Function;
    constructor(){

        this.myName = "Aman";
        this.updateName = function(input: String){

            this.inputTxt.nativeElement.value=this.myName; 

            /*assign to it the value*/
        };
    }
}

10
कृपया इस कोड को कुछ स्पष्टीकरण दें। बस स्पष्टीकरण के बिना कोड डंपिंग बहुत हतोत्साहित किया जाता है।
रयानेंग

5
यह काम नहीं करेगा: @ViewChild एनोटेशन के माध्यम से सेट की गई विशेषताएँ केवल ngAfterViewInit जीवनचक्र इवेंट के बाद उपलब्ध होंगी। कंस्ट्रक्टर में मूल्य तक पहुँचने से inputTxtउस मामले में अपरिभाषित मूल्य प्राप्त होगा ।
डेविड एम।

कोण 7 का उपयोग करते हुए, यह त्रुटिपूर्ण रूप से काम करता है।
मिज़किटा

5

नोट : यह कोणीय 6 पर लागू नहीं होता और इसके बाद के संस्करण के रूप मेंElementRefबन गयाElementRef<T>साथTके प्रकार को संकेतित करतेnativeElement

मैं यह जोड़ना चाहूंगा कि यदि आप उपयोग कर रहे हैं ElementRef, जैसा कि सभी उत्तरों द्वारा सुझाया गया है, तो आप तुरंत उस समस्या का सामना करेंगे, ElementRefजिसमें एक भयानक प्रकार की घोषणा होती है जो इस तरह दिखती है

export declare class ElementRef {
  nativeElement: any;
}

यह एक ब्राउज़र वातावरण में बेवकूफी है जहां nativeElement एक है HTMLElement

इसे हल करने के लिए आप निम्न तकनीक का उपयोग कर सकते हैं

import {Inject, ElementRef as ErrorProneElementRef} from '@angular/core';

interface ElementRef {
  nativeElement: HTMLElement;
}

@Component({...}) export class MyComponent {
  constructor(@Inject(ErrorProneElementRef) readonly elementRef: ElementRef) { }
}

1
यह एक समस्या है जो मुझे हो रही थी। यह काम नहीं करता है क्योंकि यह कहेगा कि आपको itemएक एलिमेंटरीफ होने की आवश्यकता है, भले ही आप इसे अन्य एलिमेंटरीफ पर सेट कर रहे हों let item:ElementRef, item2:ElementRef; item = item2; // no can do.:। बहुत ज्यादा उलझन। लेकिन यह ठीक है: let item:ElementRef, item2:ElementRef; item = item2.nativeElementकार्यान्वयन के कारण आपने बताया।
oooyaya

1
वास्तव में आपका पहला उदाहरण let item: ElementRef, item2: ElementRef; item = item2निश्चित असाइनमेंट विश्लेषण के कारण विफल हो जाता है। समान कारणों से आपका दूसरा विफल हो जाता है, लेकिन यदि item2चर्चा किए गए कारणों (या असाइनमेंट के लिए एक उपयोगी त्वरित जांच के रूप में हम declare letयहां उपयोग कर सकते हैं ) के लिए आरंभिक रूप से दोनों सफल होते हैं । बावजूद इसके, anyसार्वजनिक एपीआई पर इस तरह देखना वाकई शर्म की बात है ।
एलुआन हद्दाद

2

तत्काल अगले भाई पाने के लिए, इस का उपयोग करें

event.source._elementRef.nativeElement.nextElementSibling

1

सूची से लक्ष्य तत्व का चयन करना। समान तत्वों की सूची से विशेष तत्व का चयन करना आसान है।

घटक कोड:

export class AppComponent {
  title = 'app';

  listEvents = [
    {'name':'item1', 'class': ''}, {'name':'item2', 'class': ''},
    {'name':'item3', 'class': ''}, {'name':'item4', 'class': ''}
  ];

  selectElement(item: string, value: number) {
    console.log("item="+item+" value="+value);
    if(this.listEvents[value].class == "") {
      this.listEvents[value].class='selected';
    } else {
      this.listEvents[value].class= '';
    }
  }
}

HTML कोड:

<ul *ngFor="let event of listEvents; let i = index">
   <li  (click)="selectElement(event.name, i)" [class]="event.class">
  {{ event.name }}
</li>

सीएसएस कोड:

.selected {
  color: red;
  background:blue;
}

0

त्वरित उपयोग के लिए सबसे उपयुक्त उदाहरण:

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

@Component({
  selector: 'my-app',
  template:
  `
  <input #inputEl value="hithere">
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  @ViewChild('inputEl') inputEl:ElementRef; 

  ngAfterViewInit() {
    console.log(this.inputEl);
  }
}
  1. रुचि के DOM तत्व पर एक टेम्प्लेट रेफरेंस वेरिएबल डालें। हमारे उदाहरण में यह है #inputElपर <input>टैग।
  2. हमारे घटक वर्ग में @ViewChild डेकोरेटर के माध्यम से DOM तत्व इंजेक्ट करें
  3. ngAfterViewInitजीवनचक्र हुक में तत्व तक पहुँचें ।

ध्यान दें:

यदि आप डोम तत्वों में हेरफेर करना चाहते हैं तो सीधे तत्वों तक पहुँचने के बजाय Renderer2 API का उपयोग करें। DOM पर सीधी पहुँच की अनुमति देना आपके आवेदन को XSS हमलों के प्रति अधिक संवेदनशील बना सकता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.