Utilizing ControlValueAccessor in various components

I am currently working on a component that implements the ControlValueAccessor interface, and I am facing some difficulties in understanding how to properly utilize it:

// Angular Imports
import { Component, OnInit, forwardRef, Output, EventEmitter, OnChanges, Input, ViewChild } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
import { UserOrEmail } from '../entities/UserOrEmail';

// Provider for the Control Value Accessor
export const USER_INPUT_CONTROL_VALUE_ACCESSOR: any = {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => AddUserOrEmailComponent),
    multi: true,
};

const noop = () => {
    // Placeholder operation
};
@Component({
    selector: 'app-add-user-or-email',
    templateUrl: './add-user-or-email.component.html',
    providers: [USER_INPUT_CONTROL_VALUE_ACCESSOR]
})
export class AddUserOrEmailComponent implements OnInit, ControlValueAccessor {
    @Input()
    user: any = UserOrEmail;

    @Output()
    change: EventEmitter<UserOrEmail> = new EventEmitter<UserOrEmail>();

    users: any = [];
    ngOnInit() {
        this.user = {
            userId: 'ull',
            name: 'null',
            email: 'null'
        };
        this.users = ConstantService.UserArray;
    }

    // Value Accessor Interface

    private onTouchedCallback: () => void = noop;
    private onChangeCallback: (_: any) => void = noop;

    get value(): any {
        return this.user;
    }

    set value(v: any) {
        if (this.user !== v) {
            this.user = <UserOrEmail>v;
            this.onChangeCallback(v);
            this.change.next(this.user);
        }
    }

    writeValue(value: any) {
        if (value !== this.user)
            this.user = <UserOrEmail>value;
    }

    registerOnChange(fn: any) {
        this.onChangeCallback = fn;
    }

    registerOnTouched(fn: any) {
        this.onTouchedCallback = fn;
    }
}

Here is the corresponding HTML:

<div>
    <div class="form-column">
        <div class="form-row">
            <label>
                {{'GENERIC.USER'|translate}}
            </label>
            <select>
                <option [ngValue]="'default'"></option>
                <option *ngFor="let user of users" [ngValue]="user">{{user.login}}</option>
            </select>
        </div>
        <div class="form-row">
            <label for="addPersonEmail" >{{'GENERIC.EMAIL' | translate}}</label>
            <input type="email"  placeholder="{{'GENERIC.EMAIL'|translate}}" pattern="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$">
        </div>
    </div>
</div>

I have attempted to use this component in another component:

HTML:

<app-modal class="form" #addMilestoneModal [width]="550">
    <div header>{{'MODALS.ADD_MILESTONE'|translate}}</div>
    <div body>
        <div class="form-column">
            <div class="form-value">
                <app-add-user-or-email #addUser [(ngModel)]="milestone.assignee"></app-add-user-or-email>
            </div>
            <div class="form-row">
                <label for="addMilestoneDescription">{{'GENERIC.DESCRIPTION' | translate}}</label>
                <textarea style="height: 150px" [(ngModel)]="milestone.description"></textarea>
            </div>

        </div>
    </div>
    <div footer class="flex-container">
        <button class="flex-item-row btn btn-a" [disabled]="!milestone.description" (click)="apply()">{{'GENERIC.APPLY' | translate}}</button>
    </div>
</app-modal>

Typescript:

// Angular Imports
import { Component, ViewChild, EventEmitter } from '@angular/core';
import { ModalComponent } from '../../widgets/modal/modal.component';
import { Milestone } from '../../entities/Milestone';
import { ConstantService } from '../../services/ConstantService';
import { AddUserOrEmailComponent } from '../../add-user-or-email/add-user-or-email.component';

@Component({
  selector: 'app-add-milestone-modal',
  templateUrl: './add-milestone-modal.component.html'
})
export class AddMilestoneModalComponent {

  @ViewChild('addMilestoneModal')
  modal: ModalComponent;

  cs = ConstantService;

  emitter: EventEmitter<Milestone> = new EventEmitter<Milestone>();

  milestone: any = Milestone;
  apply() {
    console.log(this.milestone);
    debugger;
    this.emitter.next(this.milestone);
    this.modal.close();
  }

  cancel() {
    this.emitter.next(null);
    this.modal.close();
  }
}

However, when accessing the milestone object, it appears to be empty. What could be the issue here?

Answer №1

A few weeks back, I encountered some issues with this and decided to create a StackBlitz showcasing a helpful example.

Perhaps this could assist you as well?

Check out the StackBlitz example here

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

What is the best way to capture source code and store it in a text file?

Can you assist me in extracting the source code of a webpage and saving it into a text file? My goal: Instead of going through the process of right-clicking on the page, selecting view source code, copying, and pasting into a text file... I want to simpl ...

Trouble seeing span in ion-item in Ionic 2: How can I display plain text instead?

It seems like I may be overlooking something, as I am experiencing an issue with adding a span to an Ion Item, where the span is not being rendered, nor is the div. <ion-card> <ion-card-title> </ion-card-title> <div> < ...

Get the ability to overlay text onto an image by using jQuery for downloading

Currently, I am facing an issue with an online photo editor in my project. The problem is that I am unable to download the image after adding and editing text on it. The texts added are editable but the image cannot be downloaded after the changes. I nee ...

Prevent automatic jumping to input fields

Can someone help me with a problem related to the html input tag or primefaces p:input? I am facing an issue where the cursor always automatically jumps into the input field. The height of my page is such that scrolling is required, and the input field i ...

Empty the localStorage when terminating the IE process using the Task Manager

Utilizing HTML5 localStorage to keep track of my application session has been a useful feature. Here is a snippet of the code I am currently using: if(typeof(Storage)!=="undefined") { if(sessionStorage.lastname=="Smith") { alert("Your ses ...

The tension settings in Chart.JS appear unusual

I recently updated to ChartJS v4.0.1 and noticed a new option called tension for curving the line chart. However, I'm not satisfied with how it looks. The tension option ranges from 0 to 1, and I've experimented with different values to enhance ...

Refreshing the page after making an API call does not result in updated data

Within my VueJS application, I have implemented an API call to retrieve user statistics for display. The process involves a straightforward Java backend and utilizing an $axios get request. Upon initial page load, everything functions as anticipated. Howev ...

Node.js: Error - Module 'html' not found

Currently, I am utilizing Node.js and attempting to exclusively serve HTML files without any Jade or EJS engines. Below is the code for my entry point (index.js): var express = require('express'); var bodyParser = require('body-parser&apo ...

Alerting old session data following an AJAX request

After making an AJAX call that updates a $_SESSION variable, my <script> is supposed to echo out the new variable. However, it keeps alerting the old data even though the data is reaching the .php page and being stored in the session. I've attem ...

Is safeguarding JSON data in Javascript important?

After employing jQuery Ajax to communicate with a php script, it retrieves JSON data. This JSON Array Object is then stored in a JavaScript Variable called var myJSON = ajaxReturn; Typically, the JSON values returned are not visible in the Page Source or ...

The element 'loginToken' is not found within the type '{ loginToken: string; } | { error: Error; } | { username: string; password: string; }'

I'm currently working on creating a reducer using Typescript and Redux, but I keep running into this error: Property 'loginToken' is not recognized in type '{ loginToken: string; } | { error: Error; } | { username: string; password: str ...

Steps for making a "confirm" button within a modal that includes a redirect URL

I have developed a modal that, upon clicking on the confirm button, should redirect the user to the page titled securities-in-portfolio. modal <div class="modal-footer justify-content-center"> <button type="button" class ...

In vuex, dynamic modules share common data and do not have unique data

Currently, I am facing an issue with an asynchronous API call that returns an array of objects. After receiving this data, I map it to dynamically registered modules in my store. The process looks something like this: dispatch // prior to this dispatch, ...

Is there a way for me to utilize the imported data from one component in the context API using an arrow function?

I am trying to utilize placeInfo, reviews, detailsInfo, news from a data file. Instead of using value='hello', I am unsure if I can directly use it like this: value={placeInfo, reviews, detailsInfo, news}, as it is producing an error. Should I st ...

Having trouble with Angular Ng2-file-Upload's Upload.all() method not successfully sending files to the API

Dealing with the challenge of uploading files in mp4 and jpg formats, I have set up 2 separate instances of FileUploader with custom validation. Upon clicking the upload button, I attempt to merge the files from both instances into a single FileUploader ...

The enigmatic jQuery AJAX glitch is craving additional arguments

My website uses jQuery's ajax function to handle user signups. Despite using similar code throughout the site, I encountered an error while trying to execute the code below: Error Message: uncaught exception: [Exception... "Not enough arguments" nsr ...

Database hosted on Heroku platform

Curious to know, if you utilize Heroku for hosting, what database do you prefer? Do you lean towards PostgreSql, MongoDB, or another option altogether? I initially developed a bot using sqlite3, but quickly discovered that Heroku does not support it and ...

RTK Query - executing a query upon mounting with lazy loading enabled

Should rerendering be triggered by sending a request on mount? Or is the use of useEffect necessary? (Is lazy mode different from regular queries?) export const Catalog: React.FC<CatalogProps> = ({ object, category }) => { const [getCatalogPro ...

Issue with thymeleaf causing malfunction in top-bar navigation on foundation framework

Looking for advice on creating a navigable menu using Foundation's "top-bar" component in an HTML template file with Spring MVC + thymeleaf. The menu bar appears but the sub-menus are not displaying when hovering over them. Sub-menus related to main ...

Doesn't the use of asynchronous programming in Node.js lead to a potential StackOverflow issue?

Recently, I identified an issue with the Node.js (single-threaded) platform: As requests are handled by the server and they undergo processing until being blocked due to I/O operations. Once a request is blocked for processing, the server switches ba ...