Angular2: इसके रैपिंग टैग के बिना एक घटक को प्रस्तुत करें


100

मैं ऐसा करने का तरीका खोजने के लिए संघर्ष कर रहा हूं। मूल घटक में, टेम्पलेट एक tableऔर उसके theadतत्व का वर्णन करता है , लेकिन प्रतिनिधियों tbodyको इस तरह से एक और घटक प्रदान करता है:

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Time</th>
    </tr>
  </thead>
  <tbody *ngFor="let entry of getEntries()">
    <my-result [entry]="entry"></my-result>
  </tbody>
</table>

प्रत्येक myResult घटक अपने स्वयं के trटैग को प्रस्तुत करता है , मूल रूप से ऐसा:

<tr>
  <td>{{ entry.name }}</td>
  <td>{{ entry.time }}</td>
</tr>

इसका कारण मैं इसे मूल घटक में सीधे नहीं डाल रहा हूं (myResult घटक की आवश्यकता को टालते हुए) यह है कि myResult घटक वास्तव में यहां दिखाए जाने की तुलना में अधिक जटिल है, इसलिए मैं इसके व्यवहार को एक अलग घटक और फ़ाइल में रखना चाहता हूं।

परिणामस्वरूप DOM ख़राब दिखता है। मेरा मानना ​​है कि यह अमान्य है, क्योंकि इसमें tbodyकेवल trतत्व शामिल हो सकते हैं (MDN देखें) , लेकिन मेरा जेनरेट (सरलीकृत) DOM है:

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Time</th>
    </tr>
  </thead>
  <tbody>
    <my-result>
      <tr>
        <td>Bob</td>
        <td>128</td>
      </tr>
    </my-result>
  </tbody>
  <tbody>
    <my-result>
      <tr>
        <td>Lisa</td>
        <td>333</td>
      </tr>
    </my-result>
  </tbody>
</table>

क्या कोई ऐसा तरीका है जिससे हम एक ही चीज़ प्रदान कर सकते हैं, लेकिन रैपिंग <my-result>टैग के बिना , और अभी भी एक मेज पंक्ति को रेंडर करने के लिए एकमात्र घटक होने के लिए एक घटक का उपयोग करना?

मैं पर ध्यान दिया है ng-content, DynamicComponentLoader, ViewContainerRef, लेकिन वे जहाँ तक मैं देख सकते हैं इस के लिए एक समाधान प्रदान करने के लिए नहीं है।


क्या आप कृपया एक कार्य उदाहरण दिखा सकते हैं?
ज़कारिया एमिन

2
सही उत्तर है, प्लंकर के नमूने के साथ stackoverflow.com/questions/46671235/…
sancelot

1
प्रस्तावित उत्तर में से कोई भी काम नहीं कर रहा है, या पूरा नहीं है। सही जवाब एक plunker नमूने के साथ यहाँ वर्णित है stackoverflow.com/questions/46671235/...
sancelot

जवाबों:


97

आप विशेषता चयनकर्ताओं का उपयोग कर सकते हैं

@Component({
  selector: '[myTd]'
  ...
})

और फिर इसका उपयोग करें

<td myTd></td>

क्या आपके घटक के चयनकर्ता में शामिल है []? क्या आपने declarations: [...]किसी मॉड्यूल में घटक जोड़ा है ? यदि घटक एक अलग मॉड्यूल में पंजीकृत है, तो क्या आपने इस मॉड्यूल को अन्य मॉड्यूल में जोड़ा है imports: [...]जहां आप घटक का उपयोग करना चाहते हैं?
गुंटर ज़ोचबॉयर

1
नहीं setAttribute, मेरा कोड नहीं है लेकिन मुझे यह समझ में आ गया है, मुझे अपने टेम्पलेट में वास्तविक शीर्ष स्तर के टैग का उपयोग करने की आवश्यकता है क्योंकि मेरे घटक के लिए टैग के बजाय ng-containerनए काम का उपयोग इतना है<ul smMenu class="nav navbar-nav" [submenus]="root?.Submenus" [title]="root?.Title"></ul>
Aviad P.

1
आप एनजी-कंटेनर पर विशेषता घटक सेट नहीं कर सकते क्योंकि यह डोम से हटा दिया गया है। इसलिए आपको इसे एक वास्तविक HTML टैग पर सेट करना होगा।
रोबूस्टे

2
@AviadP। बहुत धन्यवाद ... मुझे पता था कि एक मामूली बदलाव था जो आवश्यक था और मैं इस पर अपना दिमाग खो रहा था। इसलिए इसके बजाय: <ul class="nav navbar-nav"> <li-navigation [navItems]="menuItems"></li-navigation> </ul>मैंने इसका इस्तेमाल किया (एक फीचर चयनकर्ता को ली-नेविगेशन बदलने के बाद)<ul class="nav navbar-nav" li-navigation [navItems]="menuItems"></ul>
महेश

3
यह उत्तर काम नहीं करता है यदि आप किसी सामग्री को बढ़ाने की कोशिश कर रहे हैं जैसे कि <mat-toolbar my-toolbar-row> शिकायत करेगा कि आपके पास केवल एक घटक चयनकर्ता हो सकता है एकाधिक नहीं। मैं जा सकता था <my- टूलबार-घटक> लेकिन फिर यह एक div के अंदर मैट-टूलबार डाल रहा है
रोबर्ट राजा

22

आपको "ViewContainerRef" की आवश्यकता है और मेरे परिणाम घटक के अंदर ऐसा कुछ करना है:

एचटीएमएल:

<ng-template #template>
    <tr>
       <td>Lisa</td>
       <td>333</td>
    </tr>
 </ng-template>

ts:

@ViewChild('template') template;


  constructor(
    private viewContainerRef: ViewContainerRef
  ) { }

  ngOnInit() {
    this.viewContainerRef.createEmbeddedView(this.template);
  }

4
एक जादू की तरह काम करता है! धन्यवाद। मैंने इसके बजाय @ViewChild('template', {static: true}) template;
एंगुलर

2
यह काम किया। मेरे पास एक ऐसी स्थिति थी जिसका मैं सीएसएस प्रदर्शन का उपयोग कर रहा था: ग्रिड और आपके पास अभी भी ऐसा नहीं हो सकता है <मेरे-परिणाम> टैग में माता-पिता के पहले तत्व के रूप में मेरे परिणाम के सभी बच्चे तत्वों के साथ-साथ भाई-बहन के रूप में मेरे परिणाम तक । समस्या यह थी कि एक अतिरिक्त भूत तत्व ने अभी भी ग्रिड 7 कॉलम "ग्रिड-टेम्प्लेट-कॉलम: रिपीट (7, 1 एफआर)" को तोड़ दिया है; और यह 8 तत्वों का प्रतिपादन कर रहा था। मेरे परिणाम के लिए 1 भूत स्थान धारक और 7 कॉलम हेडर। इसके लिए आस-पास का काम केवल अपने टैग में <my-result style = "display: none"> लगाकर इसे छिपाना था। सीएसएस ग्रिड प्रणाली ने उसके बाद एक आकर्षण की तरह काम किया।
RandallTo

यह समाधान एक अधिक जटिल मामले में भी काम करता है, जहां my-resultनए my-resultभाई-बहन बनाने में सक्षम होने की आवश्यकता होती है । तो, कल्पना कीजिए कि आपके पास एक पदानुक्रम है my-resultजहां प्रत्येक पंक्ति में "बच्चे" पंक्तियाँ हो सकती हैं। उस मामले में, एक विशेषता चयनकर्ता का उपयोग करने से काम नहीं चलेगा, क्योंकि पहला चयनकर्ता अंदर जाता है tbody, लेकिन दूसरा आंतरिक में नहीं जा सकता है tbodyऔर न ही एक में tr
डैनियल

1
जब मैं इसका उपयोग करता हूं तो मैं एक्सप्रेशनचेंज किए जाने से कैसे बच सकता हूं। ItHasBeenCheckedError?
गोजो कुदोर

@gyozokudor शायद एक सेटटाइमआउट का उपयोग कर रहे हैं
डिएगो फर्नांडो मुरिलो

12

अपने तत्व पर इस निर्देश का उपयोग करें

@Directive({
   selector: '[remove-wrapper]'
})
export class RemoveWrapperDirective {
   constructor(private el: ElementRef) {
       const parentElement = el.nativeElement.parentElement;
       const element = el.nativeElement;
       parentElement.removeChild(element);
       parentElement.parentNode.insertBefore(element, parentElement.nextSibling);
       parentElement.parentNode.removeChild(parentElement);
   }
}

उदाहरण का उपयोग:

<div class="card" remove-wrapper>
   This is my card component
</div>

और मूल html में, आप हमेशा की तरह कार्ड तत्व कहते हैं:

<div class="cards-container">
   <card></card>
</div>

आउटपुट होगा:

<div class="cards-container">
   <div class="card" remove-wrapper>
      This is my card component
   </div>
</div>

6
यह एक त्रुटि फेंक रहा है क्योंकि 'parentElement.parentNode' शून्य है
emirhosseini

1
विचार अच्छा है, लेकिन यह ठीक से काम नहीं कर रहा है :-(
jpmottin

9

इस मुद्दे को हल करने का सबसे अच्छा तरीका है अटेंडेंट सिलेक्टर्स।

तो आपके मामले में:

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Time</th>
    </tr>
  </thead>
  <tbody my-results>
  </tbody>
</table>

मेरे परिणाम ts

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

@Component({
  selector: 'my-results, [my-results]',
  templateUrl: './my-results.component.html',
  styleUrls: ['./my-results.component.css']
})
export class MyResultsComponent implements OnInit {

  entries: Array<any> = [
    { name: 'Entry One', time: '10:00'},
    { name: 'Entry Two', time: '10:05 '},
    { name: 'Entry Three', time: '10:10'},
  ];

  constructor() { }

  ngOnInit() {
  }

}

मेरे परिणाम HTML

  <tr my-result [entry]="entry" *ngFor="let entry of entries"><tr>

मेरे परिणाम ts

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

@Component({
  selector: '[my-result]',
  templateUrl: './my-result.component.html',
  styleUrls: ['./my-result.component.css']
})
export class MyResultComponent implements OnInit {

  @Input() entry: any;

  constructor() { }

  ngOnInit() {
  }

}

मेरा परिणाम HTML

  <td>{{ entry.name }}</td>
  <td>{{ entry.time }}</td>

वर्किंग स्टैकब्लिट्ज़ देखें: https://stackblitz.com/edit/angular-xbbegx


चयनकर्ता: 'मेरे-परिणाम, [मेरे-परिणाम]', तब मैं अपने परिणामों को HTML में टैग की विशेषता के रूप में उपयोग कर सकता हूं। यह सही जवाब है। यह Angular 8.2 में काम करता है।
डॉन दिलंगा

8

आप नए सीएसएस का उपयोग करने की कोशिश कर सकते हैं display: contents

यहाँ मेरा टूलबार scss है:

:host {
  display: contents;
}

:host-context(.is-mobile) .toolbar {
  position: fixed;
  /* Make sure the toolbar will stay on top of the content as it scrolls past. */
  z-index: 2;
}

h1.app-name {
  margin-left: 8px;
}

और HTML:

<mat-toolbar color="primary" class="toolbar">
  <button mat-icon-button (click)="toggle.emit()">
    <mat-icon>menu</mat-icon>
  </button>
  <img src="/assets/icons/favicon.png">
  <h1 class="app-name">@robertking Dashboard</h1>
</mat-toolbar>

और उपयोग में:

<navigation-toolbar (toggle)="snav.toggle()"></navigation-toolbar>

3

एक अन्य विकल्प आजकल पैकेजContribNgHostModule से उपलब्ध कराया गया @angular-contrib/commonहै

मॉड्यूल आयात करने के बाद आप host: { ngNoHost: '' }अपने @Componentडेकोरेटर में जोड़ सकते हैं और कोई रैपिंग तत्व प्रदान नहीं किया जाएगा।

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