আমি কীভাবে কোনও উপাদান টেম্পলেটটিতে একটি উপাদান নির্বাচন করতে পারি?


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);
}

স্ট্যাকব্লিটজ উদাহরণ

  • @ ভিউচাইল্ড () প্যারামিটার হিসাবে নির্দেশক বা উপাদান ধরণের বা কোনও টেম্পলেট ভেরিয়েবলের নাম (স্ট্রিং) সমর্থন করে।
  • @ ভিউচিল্ডেন () কমা বিচ্ছিন্ন তালিকা হিসাবে বর্তমানে নামের একটি তালিকা সমর্থন করে (বর্তমানে কোনও জায়গার অনুমতি নেই @ViewChildren('var1,var2,var3'))।
  • @ কনটেন্টচিল্ড () এবং @ কনটেন্টচিল্ডেন () একই কাজ করে তবে হালকা ডিওএম ( <ng-content>প্রস্তাবিত উপাদান)।

উত্তরপুরূষ

@ContentChildren() একমাত্র এটিই বংশধরদের অনুসন্ধান করতে সহায়তা করে

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

{descendants: true}ডিফল্ট হওয়া উচিত তবে ২.০.০ চূড়ান্ত নয় এবং এটি একটি বাগ হিসাবে বিবেচিত যা
এটি ২.০.১ এ স্থির করা হয়েছিল

পড়া

যদি কোনও উপাদান থাকে এবং নির্দেশ থাকে তবে 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));
}

সরাসরি ডিওএম অ্যাক্সেস

কেবল ডোম উপাদানগুলিকেই জিজ্ঞাসা করতে পারে তবে উপাদান বা নির্দেশমূলক উদাহরণ নয়:

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
গন্টার জ্যাচবাউয়ার

32
আসলে ব্যবহার ElementRefঠিক আছে। ElementRef.nativeElementসাথে ব্যবহার Rendererকরা ভাল। যা নিরুৎসাহিত করা হয় তা হ'লElementRef.nativeElement.xxx সরাসরি সম্পত্তিতে অ্যাক্সেস করা।
গন্টার জ্যাচবাউয়ার

2
@ নাটানেল আমি জানি না বা কোথায় এটি স্পষ্টভাবে নথিভুক্ত করা হয়েছে তবে এটি নিয়মিতভাবে ইস্যু বা অন্যান্য আলোচনায় (অ্যাংুলার দলের সদস্যদের দ্বারা) উল্লেখ করা হয়েছে যে সরাসরি ডোম অ্যাক্সেস এড়ানো উচিত should ডমকে সরাসরি অ্যাক্সেস করা (যা বৈশিষ্ট্যগুলি অ্যাক্সেস করার পদ্ধতি এবং এর পদ্ধতিগুলি ElementRef.nativeElement)আপনাকে অ্যাঙ্গুলার্স সার্ভার সাইড রেন্ডারিং এবং ওয়েব ওয়ার্কার বৈশিষ্ট্যটি ব্যবহার করা থেকে বিরত রাখে (আমি জানি না এটি আসন্ন অফলাইন টেমপ্লেট সংকলকটিও ভেঙে ফেলেছে - তবে আমি অনুমান করি না)
গন্টার Zöchbauer

10
পঠন বিভাগে উপরে উল্লিখিত হিসাবে , যদি আপনি ভিউচিল্ডের সাথে কোনও উপাদানটির নেটিভ এলিমেন্ট পেতে চান তবে আপনাকে নিম্নলিখিতগুলি করতে হবে: @ViewChild('myObj', { read: ElementRef }) myObj: ElementRef;
jsgoupil

203

এর মাধ্যমে আপনি ডিওএম উপাদানটির কাছে একটি হ্যান্ডেল পেতে পারেন ElementRef নিজের উপাদানটির কনস্ট্রাক্টারে ইনজেকশনের :

constructor(myElement: ElementRef) { ... }

দস্তাবেজ: https://angular.io/docs/ts/latest/api/core/index/ElementRef-class.html


1
@ ব্রোকো আপনি কি নিজের উত্তর আপডেট করতে পারবেন? আমি বর্তমান সমাধানটি দেখতে পেলাম যেহেতু ElementRefশেষ হয়ে গেছে।
জেফটোপিয়া

23
ElementRefউপলব্ধ (আবার?)।
গন্টার জ্যাচবাউয়ার

10
লিঙ্কটি যখন DOM- এ সরাসরি অ্যাক্সেস প্রয়োজন হয় তখন এই APIটিকে শেষ অবলম্বন হিসাবে ব্যবহার করুন । পরিবর্তে অ্যাঙ্গুলার দ্বারা সরবরাহিত টেম্প্লেটিং এবং ডেটা-বন্ডিং ব্যবহার করুন। বিকল্পভাবে আপনি রেন্ডারারের দিকে একবার নজর দিন যা এপিআই সরবরাহ করে যা স্থানীয় উপাদানগুলিতে সরাসরি অ্যাক্সেস সমর্থিত না হলেও এমনকি নিরাপদে ব্যবহার করা যেতে পারে। সরাসরি ডিওএম অ্যাক্সেসের উপর নির্ভর করা আপনার অ্যাপ্লিকেশন এবং রেন্ডারিং স্তরগুলির মধ্যে দৃ tight় সংযোগ তৈরি করে যা দুটিকে আলাদা করতে এবং ওয়েবকর্মীর কাছে আপনার অ্যাপ্লিকেশন মোতায়েন করা অসম্ভব করে তোলে।
সন্দীপ তালহাতুল জুলাই

@ সন্দ্বীপতলাথুলা তৃতীয় পক্ষের লাইব্রেরি থেকে ভাসমান তারিখ চয়নকারী উপাদান সংযুক্ত করার জন্য কোনও উপাদান খুঁজে পাওয়ার জন্য আরও ভাল বিকল্পটি কী? আমি জানি যে এটি আসল প্রশ্ন ছিল না, তবে আপনি এটি তৈরি করে দেখিয়েছেন যে ডমটিতে উপাদানগুলি সন্ধান করা সমস্ত পরিস্থিতিতে খারাপ ...
জন

13
@ জোহন আহ .. ঠিক আছে। আপনি এটি চেষ্টা করে দেখতে পারেন - this.element.nativeElement.querySelector('#someElementId')এবং এলিমেন্টের রেফটি এইরকম নির্মাতাকে পাস করুন .. private element: ElementRef, আমদানি করুন ...import { ElementRef } from '@angular/core';
সন্দীপ তালাথুল

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উপাদানটি অ্যাক্সেস করতে সিএসএস নির্বাচকের সাহায্যে ব্যবহার করুন।

আমি একটি ফর্ম পেয়েছি যা প্রাথমিকভাবে ইমেল ইনপুট প্রদর্শন করে। ইমেল প্রবেশের পরে, ফর্মটি তাদের প্রজেক্ট সম্পর্কিত তথ্য যুক্ত করতে চালিয়ে যাওয়ার জন্য প্রসারিত হবে। যাইহোক, যদি তারা না একটি বিদ্যমান ক্লায়েন্ট, ফর্ম প্রকল্পের তথ্য অধ্যায় উপরে একটি ঠিকানা অধ্যায় অন্তর্ভুক্ত করা হবে।

এখন পর্যন্ত, ডাটা এন্ট্রি অংশ উপাদানগুলিতে বিভক্ত হয়নি, সুতরাং বিভাগগুলি * এনজিআইফের নির্দেশ দিয়ে পরিচালিত হয়। আমার যদি প্রজেক্ট নোটের ক্ষেত্রগুলি বিদ্যমান ক্লায়েন্ট হয় তবে তারা নতুন হলে প্রথম নাম ক্ষেত্রের উপরে আমার দৃষ্টি নিবদ্ধ করা দরকার।

আমি কোনও সাফল্য না দিয়ে সমাধানগুলি চেষ্টা করেছিলাম। যাইহোক, এই উত্তরের আপডেট 3 আমাকে চূড়ান্ত সমাধানের অর্ধেক দেয়। অন্য অর্ধেকটি এই থ্রেডে ম্যাটওএনওয়াইয়ের প্রতিক্রিয়া থেকে এসেছে । ফলাফল এটি:

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কৌণিকের বাইরে কল চালাতে পারি । যেহেতু নতুন বিভাগগুলিকে রেন্ডার করার জন্য আমার সময় দেওয়া দরকার, উপাদান নির্বাচনের চেষ্টা করার আগে রেন্ডারিং থ্রেডগুলিকে সময় দেওয়ার অনুমতি দেওয়ার জন্য উপাদান বিভাগটি একটি সময়সীমাতে আবৃত হয়। সব সেটআপ হয়ে গেলে আমি বেসিক সিএসএস সিলেক্টর ব্যবহার করে উপাদানটিকে কেবল কল করতে পারি।

আমি জানি এই উদাহরণটি প্রাথমিকভাবে ফোকাস ইভেন্টটির সাথে মোকাবিলা করেছে, তবে আমার পক্ষে কঠিন যে এটি অন্যান্য প্রসঙ্গে ব্যবহার করা যায়নি।


শ্রেণি রেন্ডারার অ্যাঙ্গুলার ৪.৩.০ থেকে অবহেলিত। কৌণিক.ইও
জেমি

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

ElementRefAND 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:

এইচটিএমএল কোড:

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

টিএস কোড:

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

class TemplateFormComponent {

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

ক্লাসে এর মধ্যে যে কোনও উপাদান অ্যাক্সেস করতে এখন আপনি 'মাইফর্ম' অবজেক্টটি ব্যবহার করতে পারেন।

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
এটি কাজ করবে না: @ ভিউচিল্ড টীকাগুলির মাধ্যমে নির্ধারিত বৈশিষ্ট্যগুলি কেবলমাত্র এনজিএফটারভিউআইনিটি লাইফসাইকেল ইভেন্টের পরে উপলব্ধ। কনস্ট্রাক্টরের মান অ্যাক্সেসের inputTxtক্ষেত্রে সেই ক্ষেত্রে একটি অপরিজ্ঞাত মান পাওয়া যাবে ।
ডেভিড এম

অ্যাং 7 ব্যবহার করে, এটি নির্বিঘ্নে কাজ করেছে।
মিজআকিটা

5

নোট : এই কৌণিক 6 প্রযোজ্য নয় এবং উপরোক্ত হিসাবেElementRefওঠেElementRef<T>সঙ্গেTধরণ বাচকnativeElement

আমি যুক্ত করতে চাই যে আপনি যদি ElementRefসমস্ত উত্তরগুলির দ্বারা প্রস্তাবিত হিসাবে ব্যবহার করছেন , তবে আপনি তত্ক্ষণাত এমন সমস্যাটির মুখোমুখি হবেন ElementRefযা দেখতে ভয়ঙ্কর ধরণের ঘোষণা রয়েছে

export declare class ElementRef {
  nativeElement: any;
}

এটি ব্রাউজারের পরিবেশে নির্বোধ যেখানে নেটিমেটমেন্ট একটি 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যদিও আপনি এটা অন্য ElementRef সেটিং করছি চাহিদা, একটি ElementRef হতে: 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= '';
    }
  }
}

এইচটিএমএল কোড:

<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. আমাদের উপাদান শ্রেণিতে @ ভিউচিল্ড ডেকরেটারের মাধ্যমে DOM উপাদানটি ইনজেক্ট করুন
  3. ngAfterViewInitলাইফাইসাইকেল হুকের উপাদানটি অ্যাক্সেস করুন ।

বিঃদ্রঃ:

আপনি যদি ডিওএম উপাদানগুলি পরিচালনা করতে চান তবে উপাদানগুলিতে সরাসরি অ্যাক্সেস না করে রেন্ডারার 2 এপিআই ব্যবহার করুন। ডিওমে সরাসরি অ্যাক্সেসের অনুমতি দেওয়া আপনার অ্যাপ্লিকেশনটিকে এক্সএসএস আক্রমণে আরও ঝুঁকিপূর্ণ করে তুলতে পারে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.