Angular 1.5 components: Building applications with a component-based architecture

As stated in the Angular 1.5 documentation, components are advised to only manage their own View and Data.

Rather than directly modifying properties of objects passed to a component, it is recommended that a component creates an internal copy of the original data and uses callbacks to notify the parent component when changes occur.

In this Plunk example, I have created a demo to showcase my issue.

interface IStudent { 
  id: number,
  name: string;
}

/* SERVICE: StudentService */

public class StudentsService {
  static $inject = ['$q'];
  constructor(private $q: ng.IQService) {        
  }

  public getStudents() : ng.IPromise<IStudent[]> {
    return this.$q.when([
      { id: 1, name: 'Adam' },
      { id: 2, name: 'Ben' }
    }]);
  }  
}

/* COMPONENT: student */

class StudentsComponent implements ng.IComponent {
  public template = `<student-list on-selected="$ctrl.onSelected(student)"></student-list>
                     <edit-student student="$ctrl.student" ng-show="$ctrl.student" on-changed="$ctrl.copyChanged(copy)"></edit-student>`;
  public controller = StudentsController;
}

class StudentsController {
  private student: IStudent;

  protected onSelected(student: IStudent) {
    this.student = student;  
  }

  protected copyChanged(copy: IStudent) {
    this.student.name = copy.name;
  }
}

/* COMPONENT: student-list */

class StudentListComponent implements ng.IComponent {
  public template = '<ul><li ng-repeat="student in $ctrl.students"><a ng-click="$ctrl.onClick(student)">{{ student.name }}</a></li></ul>';
  public controller = StudentListController;
  public bindings : any = {
    onSelected: '&'
  }
}

class StudentListController {
  protected students: IStudent[];

  static $inject = ['studentsService'];
  constructor(private studentsService: StudentsService) {
  }

  public $onInit() {
    this.studentsService.getStudents().then(data => this.students = data);
  }

  protected onClick(student: IStudent) {
    this.onSelected({ student: student });
  }
}

/* COMPONENT: edit-student */

class EditStudentComponent implements ng.IComponent {
  public template = `<form class="form">
                       <div class="input-group">
                         <label for="#" class="control-label">Original</label>
                         <input type="text" class="form-control" ng-model="$ctrl.student.name" readonly>
                        </div>
                      </form>
                      <form class="form">
                       <div class="input-group">
                         <label for="#" class="control-label">Copy</label>
                         <input ng-change="$ctrl.changed()" type="text" class="form-control" ng-model="$ctrl.copy.name">
                        </div>
                      </form>`;
  public controller = EditStudentController;
  public bindings :any = {
    student: '<',
    onChanged: '&'
  };
}

class EditStudentController  {
  protected copy: IStudent;

  public $onInit() {
    console.log('EditStudentComponent.$onInit', this.student);
  }

  public $onChange() {
    console.log('EditStudentComponent.$onChange', this.student);
    this.copy = angular.copy(this.student);
  }

  protected changed() {
    console.log('EditStudentController.changed', this.copy);
    this.onChanged({ copy: this.copy });
  }
}

/* Bootstrap */

angular
  .module('app', [])
  .component('students', new StudentsComponent())
  .component('studentList', new StudentListComponent())
  .component('editStudent', new EditStudentComponent())
  .service('studentsService', StudentsService)
;

angular.bootstrap(document, ['app']);

I have a list of students where each selection triggers a textbox allowing users to modify the name of the selected student. However, after selecting a student, the edit-user component fails to initialize properly and displays the initial copied name (null).

If anyone can assist me in resolving this Plunk issue so that clicking on a student initializes the edit component with a copy of the selected student, it would be greatly appreciated.

Edit: I've updated the Plunk as there was an accidental removal of the script tag instead of the style tag.

Answer №1

Initially, I believed that this plunk would provide the solution to my issue. However, it turned out that the plunk was not effective due to my use of $onChange instead of $onChanges. Once I corrected this error, the plunk functioned as intended.

The root cause of my original problem differed from what I had initially thought. Within my business application, I incorporated another component with a ng-transclude directive surrounding my edit component in the following manner:

<modal-editor>
    <edit-student data="$ctrl.data">
    <edit-student>
</modal-editor>

Since the edit-student component was defined within the isolated scope of the modal-editor component, it did not receive updates to the data variable in the outer scope (despite still being able to access this external data).

To resolve this issue, I adjusted the modal-editor component to pass the data to the child component, resulting in the desired functionality:

<modal-editor data="$ctrl.data">
    <edit-student data="$ctrl.data">
    <edit-student>
</modal-editor>

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

Using *ngFor to populate an array in an ion-list within Ionic 2

Hi there, I'm currently learning Ionic 2 and I recently created an array that I want to loop through in an ion-list. This is my produk.ts import { Component } from '@angular/core'; import { NavController, NavParams } from 'ionic-angul ...

Creating test cases for a service that relies on a Repository<Entity> to consume another service

Having trouble creating tests for an auth.service that seems pretty straightforward from the title. However, every time I run the tests, I encounter this error: TypeError: Converting circular structure to JSON --> starting at object with cons ...

Firestore database transactions not living up to our expectations

When attempting firebase database transactions, they fail without throwing any errors. Here is the relevant code snippet: Code: import * as admin from "firebase-admin"; const db = admin.firestore(); class Doc { first = 0; second = 0; thi ...

Setting up dynamic routing in AngularJS for links

I am facing some confusion regarding routing in AngularJS. Normally, we can configure routes in angular.config() when the angular module is loaded. At that time, we define static information such as routePath, templateUrl, and controller. However, I am u ...

A universal function that uses an array parameter to create a custom type

My function takes an array as a parameter and constructs the generic type passed in by the array. Everything is working fine, but I want to add a type check to ensure that the keys of the array match the properties of the generic type, otherwise it should ...

Problem encountered when running "npm install" following the configuration of an AngularJS project using Yeoman

Encountering an issue during or after the creation of an Angular project using the command: yo angular While installing devDependencies from the package.json ("npm install" which is triggered by yo angular), I noticed certain modules were missing in the ...

Enhancing Vue prop with TypeScript typing

In my Vue component, I am working with a prop called tabs. The format for this prop is expected to be as follows: [{ id: string title: string color: `#${string}` },{ id: string title: string color: `#${string}` }] Currently, I am utilizing Lar ...

Adjusting the hue of a mat-form ripple based on certain conditions

I am currently developing an angular application and using mat-form-field in the following manner. <mat-form-field appearance="fill"> <mat-label id="title">{{ title }} </mat-label> <input formControlName ...

Unable to set up Angular 1.5 component router

Struggling to incorporate the Angular 1.5 component router into a new project has been quite challenging for me. According to the instructions provided at https://docs.angularjs.org/guide/component-router, running the following command should do the trick: ...

AngularJS view not rendering template directive

I am looking to create a directive that will respond to a click event on a DOM element. The directive should call a service that returns a string, and then display the string along with some HTML template. However, currently, the template is not being disp ...

End the nodejs aws lambda function within a .then or .catch block

Here is an AWS lambda function written in nodejs: export const handler: APIGatewayProxyHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => { var file; await getFile() .then((filedata): void => { file ...

Tips for updating information when integrating AngularJS with MongoDB

Embarking on my journey as a novice in the AngularJs and MongoDb realm today! My current endeavor is quite straightforward: showcase a list of records, featuring an add button along with an edit link for each entry. Utilizing the library https://github.c ...

Is there a method in RXJS that allows an operator to pause and wait for a subscription to finish before proceeding with the workflow?

Being new to the world of RXJS, I have spent a considerable amount of time researching and seeking solutions on stackoverflow and various documentation sources before turning to ask for help here. However, despite my efforts, I am struggling to make my log ...

Encountering a "args" property undefined error when compiling a .ts file in Visual Studio Code IDE

I've created a tsconfig.json file with the following content: { "compilerOptions": { "target": "es5" } } In my HelloWorld.ts file, I have the following code: function SayHello() { let x = "Hello World!"; alert(x); } However ...

Can you explain the significance of the additional pipeline in the type declaration in TypeScript?

Just recently, I defined a type as follows- interface SomeType { property: { a: number; b: string; } | undefined; } However, upon saving the type, vscode (or maybe prettier) changes it to- interface SomeType { property: | { a: nu ...

Receiving errors in React/TS/material-ui when attempting to use a variable as a value for a grid property. Messages include "No overload matches" and "Type 'number' is not assignable to type..."

tl;dr: When using a variable as the value of a grid xs property in JSX, material-ui throws a TS error. I'm working on implementing grids in material-ui with React/TypeScript. The goal is to make the width of a specific element dependent on the quant ...

What is the best way to include variable child directives within a parent directive in AngularJS?

Exploring a New Angular Challenge In the current project I am engaged in, I am faced with a unique problem that requires an 'angular way' solution. Despite my best efforts, I seem to be hitting a roadblock every time I attempt to solve it. The ...

I am having trouble with my quiz function as it only checks the answer correctly for the first question. Does anyone have suggestions on how to make it work for

Currently, I'm tackling a quiz project that was assigned to me during my bootcamp. My focus right now is on the checkAnswer function, which evaluates the answer selected by the player. const startButton = document.querySelector(".start") as ...

Trouble with a basic Angular demonstration

After replicating an angular example from w3schools (found here), I encountered some issues with it not functioning correctly. Despite my efforts, the code appears to be accurate. Can anyone spot what might be going wrong? To provide more context, here is ...

Storing references to the DOM elements external to the rendering component

Just diving into the world of Electron + Typescript, so please bear with me. Currently, I'm experimenting with what can be achieved within Electron. Issue: My goal is to manipulate DOM elements outside of the renderer. I pass a button as a parameter ...