The data type 'string[]' cannot be assigned to the data type 'listData[]'

I'm currently developing a flexible component that allows the list view to be utilized by different components. However, the challenge arises from the fact that each component has a different data format. In my project, I'm unable to use type any[] due to linting issues that cannot be circumvented.

list-view.component.html(shared component)

          <div *ngFor="let list of lists">
              <ng-template #defaultTemplate>
                  <p> {{list}}</p>
             </ng-template>
             <ng-container
              [ngTemplateOutlet]="optionTemplate || defaultTemplate"
              [ngTemplateOutletContext]="{ $implicit: list}"
             >
            </ng-container>
          </div>

list-view.component.ts

          import {Component,ContentChild,EventEmitter,Input,Output,TemplateRef} from '@angular/core';

          export interface listData{
             id: number;
             brand: string;
             model: string;
             url: string;
          }

          @Component({
             selector: 'app-my-selector',
             templateUrl: './my-selector.component.html',
          })
           export class MySelectorComponent {
               @Input() lists: listData;  **// can't use any[], because of linting issue.**
               @ContentChild('optionTemplate', { static: false }) optionTemplate: TemplateRef;
               constructor() {}
           }

test1.component.html

           <div class="container">
              <app-my-selector [lists]="list">
                  <ng-template #optionTemplate let-list>
                       <img src="{{list.url}}" alt="{{list.model}}">
                       <p>{{list.brand}}: {{list.model}}</p>
                  </ng-template>
              </app-my-selector>
            </div>

test1.component.ts

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

             export interface listData{
               id: number;
               brand: string;
               model: string;
               url: string;
             }
             @Component({
                  selector: 'app-test1',
                  templateUrl: './test1.component.html',
             })
             export class Test1Component {
                 list:listData[];
                 constructor() {}
                 ngOnInit() {
                     this.list = [
                      {
                          id: 1,
                          brand: 'TATA',
                          model: 'Indica - 2008',
                          url: '/indica-img.jpg'
                      },
                      {
                          id: 2,
                          brand: 'Suzuki',
                          model: 'Swift - 2011',
                          url: '/swift-img.jpg'
                      }
                   ];
                 }
                }

test2.component.html

                   <div class="container">
                      <app-my-selector [lists]="list"></app-my-selector>
                   </div>

test2.component.ts

                   import { Component, OnInit } from "@angular/core";
                   @Component({
                        selector: "app-test2",
                        templateUrl: "./test2.component.html",
                   })
                   export class Test2Component {
                      list: string[];  **// this is where causing the issue.**
                      constructor() {}
                      ngOnInit() {
                         this.list = ['Harley Davidson','Bajaj','Triumph'];
                      }
                    }

If I run the above code I am getting Type 'string[]' is not assignable to type 'listData[]' in test2.component.html. Because the test1 component is an array of object data & the test2 component is an array of data. So without using any[] how can I achieve this?

Answer №1

One good suggestion mentioned in the comments is to consider using a generic type.

You can try implementing it like this:

@Component({
   selector: 'app-my-selector',
   templateUrl: './my-selector.component.html',
})
export class MySelectorComponent<T> {
   @Input() lists: T[];  // It's recommended not to use any[], due to linting issues.
   @ContentChild('optionTemplate', { static: false }) 
   optionTemplate: TemplateRef<T>;
   constructor() {}
}

Additionally, you might want to check out this article for guidance on creating reusable components in Angular.

Answer №2

Although I couldn't replicate the issue, upon further investigation, I discovered several enhancements that could be proposed...

import { CommonModule } from '@angular/common';
import { Component, ContentChild, Input, NgModule, TemplateRef } from '@angular/core';

// Adjust ListData to have capitalized first letter in properties
export interface ListData {
  id: number;
  brand: string;
  model: string;
  url: string;
}

@Component({
  selector: 'test-parent',
  // Assign the container class directly to the host component (apply display: block)
  host: { class: 'container' },
  template: `
    <!-- Remove unnecessary div node and add a class directly -->
    <test-child [lists]="list">
      <ng-template #optionTemplate let-list>
        <!-- Use property binding instead of interpolation for attributes -->
        <img [src]="list.url" [alt]="list.model" />
        <p>{{ list.brand }}: {{ list.model }}</p>
      </ng-template>
    </test-child>
  `,
})
export class TestComponentParent {
  list: ListData[] = [
    {
      id: 1,
      brand: 'TATA',
      model: 'Indica - 2008',
      url: '/indica-img.jpg',
    },
    {
      id: 2,
      brand: 'Suzuki',
      model: 'Swift - 2011',
      url: '/swift-img.jpg',
    },
  ];

  // ngOnInit() {}; Initialize component property without waiting for this lifecycle hook
}

@Component({
  selector: 'test-child',
  template: `
    <!-- Combine structural directive and attribute directive in the same container without additional div node -->
    <ng-container
      *ngFor="let list of lists"
      [ngTemplateOutlet]="optionTemplate || defaultTemplate"
      [ngTemplateOutletContext]="{ $implicit: list }"
    >
    </ng-container>

    <!-- Eliminate redundant template creation for each iteration in the loop -->
    <ng-template #defaultTemplate let-list>
      <p>{{ list }}</p>
    </ng-template>
  `,
})
export class TestComponentChild {
  // Ensure lists is an array: ListData[], not an instance of ListData
  @Input() lists: ListData[];

  // Consider removing static property if unnecessary since most Angular versions default it to false
  @ContentChild('optionTemplate', { static: false }) optionTemplate: TemplateRef<any>;
}

@NgModule({
  declarations: [TestComponentParent, TestComponentChild],
  imports: [CommonModule],
})
export class FeatureModule {}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for maintaining focus on an editable div using jQuery

Is there a way to prevent an editable div from becoming unfocused when clicking on a formatting bar created using jQuery? I've been trying to implement this feature but can't seem to figure it out. Any advice would be greatly appreciated. Many th ...

How do I switch the background-image on li hover and revert it back when I move off the li element?

Looking to update the background image of a div upon hovering over a li element? Check out this example here. So far, I've got that part working fine. But now I want the background picture to revert back to its original CSS when I move away from the l ...

Pausing JavaScript Execution Until the Completion of an Ajax Call

As I edit values in a form fetched from the database via AJAX, clicking an element opens a modal box. The details are then fetched from the server and placed in the appropriate form elements. The data contains a pin code, and I need to retrieve all the ar ...

Is it possible to sketch basic 2D shapes onto 3D models?

Is the technique called projective texture mapping? Are there any existing library methods that can be used to project basic 2D shapes, such as lines, onto a texture? I found an example in threejs that seems similar to what I'm looking for. I attempt ...

Creating an ESNext JavaScript file and integrating it into an Angular 2 project: A comprehensive guide

I am facing an issue with my js file named UserService.js and source.js, which has been transformed using transformer typescript. My objective is to integrate this transformed js file into Angular. UserService.js import { Source } from "./source" ...

Tips for setting up a personalized preview mode in Sanity Studio using Next.js

I am facing an issue displaying the preview mode because the URL must contain specific parameters such as "category" and "slug" (as shown in the image below). Here is the error URL with undefined parameters Therefore, I am unable to retrieve the paramete ...

Enhancing State in React Component through Prop Update

I am aiming to achieve the functionality of clicking a button in a child component and having that component removed. I am new to React and currently in my app.js file, I have a component with a prop like this: <IntroSteps isHidden={false} /> Inside ...

Issue: [ng:areq] The function 'DepartmentCustomReportController' is missing and undefined in Internet Explorer

I am encountering an issue specifically in Internet Explorer, as the same controller works without any problems in Chrome. Here is a snippet of my index.html file: <script src="assets/js/boostrapJs/jquery-1.11.1.min.js"></script> <script s ...

"Enhance your web app with Emotion.js and Preact SSR, complete with

In my preact SSR application, I have utilized Emotion JS 10 for styling purposes. My goal was to incorporate RTL support into the app. To achieve this, I implemented createEmotion and createEmotionServer, leveraging the resulting renderStylesToString to r ...

sending the properties from the menu component to the dish details

Having trouble with a react.js app I'm working on that involves rendering dish cards. The dish object is always null when passed as props from MenuComponent to DishDetail, resulting in nothing being displayed on the screen. Can someone please assist m ...

Activate a CSS class on click using JavaScript

Having a bit of trouble as a beginner with this. Any help would be much appreciated. This is the code in question: HTML: <div class='zone11'> <div class='book11'> <div class='cover11'></d ...

Angular 2.0's development of modules and implementation of shadow DOM focuses on supporting a left

My website supports "right to left" languages like Arabic. When the language is Arabic, I add the dir="rtl" attribute to the body tag. This aligns all inline positioned children from the right side, even within custom components. Now, I want a custom styl ...

Upgrade your function to utilize Firebase V9 with Next.js framework

I recently updated my project to use version 9 of firebase, and since then, I've been encountering some code errors that I'm struggling to resolve. The previous function had the following structure, but now I need to update it to work with the n ...

Having issues as a Node.js novice with error messages

Here is the code I have for a basic node.js application: var http = require('http'); var fs = require('fs'); var path = require('path'); var url = require('url'); var port = process.env.port || 1337; http.createSer ...

Unable to retrieve the headers from the error response

When working with Angular 6, I encountered an issue where I couldn't retrieve the headers from an HTTP error response. Specifically, when the server responded with a status code of 401, additional headers were included in the error response. What is t ...

Can README docs be prioritized to appear before all other stories in Storybook navigation?

Organizing my Storybook stories is important to me. I like to nest all my stories under a “Docs” header, with each component having a README mdx file followed by its stories. My preferred order is to always have the README appear first in the navigatio ...

The Mean Stack by Bitnami

After setting up the Mean Stack Manager, I encountered an issue. When running a command in the node terminal like console.log("Hello World"), it runs smoothly. However, if I place a Javascript sample file in any folder within the mean stack install directo ...

This function has a Cyclomatic Complexity of 11, exceeding the authorized limit of 10

if ((['ALL', ''].includes(this.accountnumber.value) ? true : ele.accountnumber === this.accountnumber.value) && (['ALL', ''].includes(this.description.value) ? true : ele.description === this.description.valu ...

JQuery Script Perform an Action - Pause - Execute Another Action

I'm working on a function that involves running some jQuery code, pausing for around 5 seconds, and then executing something else. Here's an example of what I'm trying to achieve: function myFunc() { var str1 = 'This is the starti ...

The functionality of NgbModal in ng-bootstrap is experiencing issues and becoming unresponsive in ng-bootstrap version 15 and Angular version 16

Currently, I am in the process of upgrading my Angular app from version 15 to version 16. Following the documentation, I have updated the @ng-bootstrap/ng-bootstrap package to version 15. However, after this update, I am facing issues with the NgbModals no ...