Is there a disparity in capabilities or drawbacks between ViewChild and Input/Output in Angular?

As I delve into Angular ViewChild and compare it to Input/Output parameters, I can't help but wonder if ViewChild has any drawbacks or limitations compared to Input/Output.

It appears that ViewChild is the preferred method, as all parameters are now centralized in Typescript. This eliminates the need to mix code with HTML markup, allowing for a cleaner separation of business/data logic parameters.

ViewChild

@ViewChild(AddressTypeDropdownComponent, { static: false }) child: AddressTypeDropdownComponent;

ngAfterViewInit() {
  // Subscribe to the child component event
  this.child.addressTypeChange.subscribe(value => {
    console.log(value);
  });
}

someMethod() {
  // Set the input values of the child component
  this.child.addressTypeDefaultItem = someValue1;
  this.child.selectedAddressType = someValue2;
}

Input/Output

<app-address-type-dropdown 
    (addressTypeChange)="addressTypeChangeEvent($event)"
    [addressTypeDefaultItem]="someValue1"
    [selectedAddressType]="someValue2">
</app-address-type-dropdown>

Answer №1

Expanding on the previous answer, utilizing [ ] and ( ) within HTML itself is incredibly descriptive of its functionality. Angular's core concept revolves around HTML components.

By breaking down the DOM into components, reusability is enhanced. When implementing such components (like angular material), it's essential for users importing them as libraries to understand the necessary @Input parameters and emitted @Output events. This way, when encountering these components in code, users can easily grasp how they operate.

Lack of proper representation leads to confusion for users. For example, check out this example.

With @Input and @Output:

<button mat-raised-button (click)="addColumn()"> Add column </button>
<button mat-raised-button (click)="removeColumn()"> Remove column </button>
<button mat-raised-button (click)="shuffle()"> Shuffle </button>

<table mat-table [dataSource]="data" class="mat-elevation-z8">
  <ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">
    <th mat-header-cell *matHeaderCellDef> {{column}} </th>
    <td mat-cell *matCellDef="let element"> {{element[column]}} </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
  <tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
</table>

Without

<button mat-raised-button #add> Add column </button>
<button mat-raised-button #remove> Remove column </button>
<button mat-raised-button #shuffle> Shuffle </button>

<table mat-table class="mat-elevation-z8">
  <ng-container *ngFor="let column of displayedColumns">
    <th mat-header-cell *matHeaderCellDef> {{column}} </th>
    <td mat-cell *matCellDef="let element"> {{element[column]}} </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
  <tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
</table>

Which code do you find more readable?

Additionally, consider how to handle simple events like (click), (keyup), or [routerLink].

While workarounds are possible, readability and developer-friendly practices should be maintained. Sometimes, segregating functionalities helps clarify their purpose within the codebase, a principle applicable across all software languages.

Answer №2

When it comes to preferences, I typically opt for using ViewChild/ren to manipulate the DOM, similar to how we used jQuery in the past to alter native HTML elements. For data binding and controlling a child component's state from the parent, I prefer using input/output to keep the child isolated and stateless.

An example from the Angular documentation - https://angular.io/api/core/ViewChild

In this example, you can observe that the ID property is passed as an input to the pane component, while visibility is managed by the parent.

If there was a button inside the pane that toggles visibility, you could add an output to the pane component that emits the toggle state change to the parent. The parent would still utilize ViewChild to update the child's state.

One drawback of setting child component properties directly is that it isn't reactive and won't trigger Angular's change detection like input/output does (Angular automatically watches those properties).

Testing such a component can be challenging since the child component isn't aware of its own state changes controlled by the parent. In testing, they must be treated as one entity.

In general, altering component attributes in this manner is considered poor practice as it can disrupt Angular's change detection process, requiring manual management with changeDetectorRef.

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

Creating a connection between properties and their values

I am looking to implement a property for data binding on my own terms. For instance, consider the following list of items: [{name='name1', invalid='error.name1'}] Along with another list of errors. errors : any= ['name1': & ...

Angular's import and export functions are essential features that allow modules

Currently, I am working on a complex Angular project that consists of multiple components. One specific scenario involves an exported `const` object in a .ts file which is then imported into two separate components. export const topology = { "topolo ...

How can I make sure that the combobox in my Ionic app is aligned with the text fields in a row?

From the image provided, it's evident that my HTML code looks like this: <ion-row> <ion-col> <ion-item> <searchable-ion-select isModal="true" name="country" valueField="code" [(ngModel)]="country" title="Country" ...

Encountered an issue in Typescript with error TS2554: Was expecting 0 arguments but received 1 when implementing useReducer and useContext in React

I've encountered several errors with my useReducers and useContext in my project. One specific error (TS2554) that I keep running into is related to the AuthReducer functionality. I'm facing the same issue with each Action dispatch. I've tri ...

The error message "TypeError: 'undefined' is not an object ('_this.props')" indicates that the property '_this

Having trouble solving this issue. Need assistance with evaluating 'this.props.speciesSelection.modalize' <BarcodeInput speciesSelection={this.props.speciesSelection} species={species[0]} barcode={{ manufacturerValue: ...

Ensuring type safety in TypeScript arrow function parameters

I have encountered an issue with my code when setting "noImplicitAny" to true. import ...; @Injectable() export class HeroService { private _cachedHeroes: Observable<Hero[]>; private _init: boolean; private _heroesObserver: Observer<Hero[ ...

Ways to vertically adjust text using ngStyle depending on the condition

I've been attempting to conditionally align text using ngStyle, but I haven't had any success yet. This is the code I have come up with so far: <div [ngStyle]="{'display':totalRegisters<=10 ? 'inline-block; text-align: ...

Positioning Placeholder in Angular Material's mdInput

I am currently in the process of designing a Form for my website, but I am encountering an issue with the Input and its Placeholder. The implementation should be straightforward, resembling something similar to this. However, the Placeholder is appearing ...

Setting up ESM for Firebase functions: A step-by-step guide

Our server application needs to utilize the most recent ipfs-http-client as it is an authorized package for accessing IPFS. However, the project must switch to using ESM starting from v57.0.0. I have invested a significant amount of time into this and it h ...

Tips on obtaining data from ion-select and presenting it in a label

I'm having a problem with dynamic binding in my drop-down. I can't seem to display the default selected value in the label, and when I change the selection, the new value isn't showing up either. Take a look at my code below: <p>{{l ...

Setting the base href in Angular using an environment variable for a Tomcat or other application server - a step-by-step guide

Is it possible to set the base href using an environment variable in a Tomcat or application server? For instance: index.html <base href="/${environment.tomcat}/"> Or is there a way to utilize an environment variable for the operating system? ...

Is it possible to inject a descendant component's ancestor of the same type using

When working with Angular's dependency injection, it is possible to inject any ancestor component. For example: @Component({ ... }) export class MyComponent { constructor(_parent: AppComponent) {} } However, in my particular scenario, I am tryin ...

The `setState` function is failing to change the current value

I'm having an issue with setting State in the dropdown component of semantic-ui-react while using TypeScript in my code. The selected category value is always returning an empty string "". Any suggestions on how to resolve this problem? impo ...

Leveraging the expand function for pagination through recursive invocations

I am currently working on retrieving data from a third party API that necessitates manual management of paging by keeping track of the number of records retrieved versus the total number of records available. In attempting to handle this, I experimented w ...

Can you explain the distinction between the controls and get methods used with the FormGroup object?

I have encountered an interesting issue with 2 lines of code that essentially achieve the same outcome: this.data.affiliateLinkUrl = this.bookLinkForm.controls['affiliateLinkUrl'].value; this.data.affiliateLinkUrl = this.bookLinkForm.get(' ...

Elevate the Appearance of Material UI Elements with custom CSS Sty

I am currently facing an issue while trying to customize the styling of a Material UI component using CSS. Here is the code snippet: <IconButton className="my-class"> <Close /> </IconButton> CSS: .my-class { float: right ...

Header remains fixed when scrolling

Is there a way to make the header of a Bootstrap table fixed when scrolling, while also adjusting the width of each column based on the content within it? I want the column headers to match the width of the row with the most text. Setting the position of t ...

How can I pass a service method as a parameter in an Angular 2 component?

Within the component: myFunction(): void { this.myOtherFunctoin(this._myService.serviceMethod); } private myOtherFunction(func : Function){ func(); } Regarding service calls: serviceMethod(){ this.somethingMethod(); // "this" is coming as ...

Exploring Vue with Typescript - leveraging components without explicit definitions

Has anyone successfully used vue-instant component as a child component before? I'm having trouble adding components without definition. Could it be related to webpack config ignoring node_modules due to lack of type declaration? Here's the code ...

Tips for modifying date format in Angular 8

My datepicker for a date column is displaying the incorrect date format after submission. I am looking to change this format to the correct one. I am working with bsConfig bootstrap in Angular 8, but I am unsure of how to modify the date format. The back ...