Total Pageviews

Showing posts with label Angular2. Show all posts
Showing posts with label Angular2. Show all posts

2017/04/04

[Angular2] fail to load data items in ng2-select component

Problem
I am using ng2-select to implement a dropdown list function.
But my dropdown list cannot be showed just like the example:


Here is my code snippet:
   <div class="row">
    <div class="col-sm-12">
        <div class="form-group">
           <label> 負責人員 </label>
           <div style="width: 300px; margin-bottom: 20px;">
              <ng-select [allowClear]="true" 
                         [items]="items" 
                         [data]="selectedItem"
                         (data)="refreshValue($event)" 
                         (selected)="selected($event)"
                         (removed)="removed($event)" 
                         placeholder="請選擇負責人員">
              </ng-select>
           </div>
        </div>
    </div>
   </div>


How-to
Owning to the data items in ng2-select example is static:

The data items in my function which will retrieve them from 
database, so we need to wait until data items had been finished then create the DOM element.

Owing to I do not know how long I need to wait, so I add *ngIf in the first div tag.
   <div class="row" *ngIf="items && items.length > 0">
    <div class="col-sm-12">
        <div class="form-group">
           <label> 負責人員 </label>
           <div style="width: 300px; margin-bottom: 20px;">
              <ng-select [allowClear]="true" 
                         [items]="items" 
                         [data]="selectedItem"
                         (data)="refreshValue($event)" 
                         (selected)="selected($event)"
                         (removed)="removed($event)" 
                         placeholder="請選擇負責人員">
              </ng-select>
           </div>
        </div>
    </div>
   </div>


Reference
[1] https://valor-software.com/ng2-select/


2017/03/10

[Agnular2] Notifying parent Components that something has happened via events

Scenario

If we would like to tell the parent Component that the child component has added or deleted subtask. How to implement in Angualr2 ?


How-to
To create a custom event, we can use the new @Output decorator. So let's start by creating a new instance of an Event Emitter and decorate the property with the @Output decorator.

Then we've got an event emitter in place, let's call its emit method, callParent(), to raise the event and pass to parent component. 

The child component's code snippet looks like:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@Component({
  selector: 'sub-task',
  directives: [MODAL_DIRECTIVES, SELECT_DIRECTIVES, NgClass],
  providers: [SubtaskService, UserService, IssueService, ProjectService],
  templateUrl: 'sub.task.html'
})
export class SubTaskComponent implements OnInit {

  @Input() issue: Issue;
  @Input() watchers: Watcher[];

  @Output() refreshIssueEvent = new EventEmitter();
  
  callParent() {
    this.refreshIssueEvent.emit(this.issue.id);
  }
  
  //...
}  


The parent component receives that event and its payload. We use event binding to bind to this notify event and call a method.

Our final step is to provide the refreshIssue method to execute when the notify event occurs. 
1
2
3
<div class="container" *ngIf="issue.id">
  <sub-task [issue]="issue" [watchers]="issue.watchers" (refreshIssueEvent)="refreshIssue($event)"></sub-task>
</div>

We have to pass the $event to parent component's handler because that variable holds the event payload.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Component({
  selector: 'issue-detail',
  templateUrl: 'issue.detail.html',
  providers: [IssueService]
})
export class IssueDetailComponent implements OnInit, OnDestroy {
  refreshIssue(issueId: number){
    this.issueService.getIssue(issueId.toString()).subscribe(
      data => {
        this.issue = data;
      }
    );
  }
  //...
}

2017/03/09

[Angular2] Pass data from parent to child with input binding

Scenario


If we had two html pages which has parent and child relationship. If we would like to pass parameters from parent to child, how to implement in Agnular2?

How-to
Step 1. Define the input parameter names in child component which typically adorned with @Input decorations., the code snippet is as bellows:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Component({
  selector: 'sub-task',
  directives: [MODAL_DIRECTIVES, SELECT_DIRECTIVES, NgClass],
  providers: [SubtaskService, UserService, IssueService, ProjectService],
  templateUrl: 'sub.task.html'
})
export class SubTaskComponent implements OnInit {

  @Input() issue: Issue;
  @Input() watchers: Watcher[];
  
  // ...
}

Step 2. The Parent page, issue.detail.html, is binding its master string property to the child's property. The code snippet is as follows:
1
2
3
<div class="container" *ngIf="issue.id">
  <sub-task [issue]="issue" [watchers]="issue.watchers"></sub-task>
</div>



2017/03/05

[Angular2] Fail to apply bootstrap on checkbox with Angular2

Problem
According to the example in w3schools, http://www.w3schools.com/bootstrap/bootstrap_forms_inputs.asp

If the checkbox is static, it will not have this problem. But if the checkboxes generate dynamically, using *ngFor, the checkbox square is missing


The code snippet is as bellows:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<div class="row" *ngIf="roles">
   <div>
      <label>角色</label>
   </div>
   <div *ngFor="let role of roles" style="display: inline-block">
      <div class="checkbox">
         <label style="padding-right:10px; padding-left:10px" >
         <input type="checkbox" [(ngModel)]="role.isSelected" (change)="checkRole(role)">
         {{ role.name }}
         </label>
      </div>
   </div>
</div>


How-To
It seems that if the checkbox generate dynamically, it will lack of some html tags to assign class for unknown reasons. Therefore, you need to add these span tag manually (line 9).  

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<div class="row" *ngIf="roles">
   <div>
      <label>角色</label>
   </div>
   <div *ngFor="let role of roles" style="display: inline-block">
      <div class="checkbox">
         <label style="padding-right:10px; padding-left:10px" >
         <input type="checkbox" [(ngModel)]="role.isSelected" (change)="checkRole(role)">
         <span class="checkbox-material"><span class="check"></span></span>
         {{ role.name }}
         </label>
      </div>
   </div>
</div>




2017/02/07

[Angular2] Label Text Padding

Problem
This is my original modal dialog:


I hope the label can be looks like (it will be looks more pretty):



Here has the original code snippet:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<modal #newUserModal [size]="'lg'">
  <modal-header [show-close]="true">
    <h4 class="modal-title">新增用戶</h4>
  </modal-header>

  <modal-body>
    <div class="row">
      <button type="button" class="btn btn-primary btn-raised" style="float: right;" (click)="newUserModal.close();"> 取消 </button>
      <button type="button" class="btn btn-primary btn-raised" style="float: right;" (click)="createUser()"> 儲存 </button>
    </div>

    <div class="row">
      <div class="col-sm-10 form-inline">
        <label>帳戶名稱</label>
        <input type="text" class="form-control" id="login" [(ngModel)]="newUser.login" required>
      </div>
    </div>

    <div class="row">
      <div class="col-sm-10 form-inline">
        <label>名字</label>
        <input type="text" class="form-control" id="lastName" [(ngModel)]="newUser.lastName" required>
      </div>
    </div>

    <!-- ignore some code -->

  </modal-body>
</modal>


How-To
We can add padding-left for each label, the padding-left property sets the left padding (space) of an element.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<modal #newUserModal [size]="'lg'">
  <modal-header [show-close]="true">
    <h4 class="modal-title">新增用戶</h4>
  </modal-header>

  <modal-body>
    <div class="row">
      <button type="button" class="btn btn-primary btn-raised" style="float: right;" (click)="newUserModal.close();"> 取消 </button>
      <button type="button" class="btn btn-primary btn-raised" style="float: right;" (click)="createUser()"> 儲存 </button>
    </div>

    <div class="row">
      <div class="col-sm-10 form-inline">
        <label style="padding-left:64px">帳戶名稱</label>
        <input type="text" class="form-control" id="login" [(ngModel)]="newUser.login" required>
      </div>
    </div>

    <div class="row">
      <div class="col-sm-10 form-inline">
        <label style="padding-left:96px">名字</label>
        <input type="text" class="form-control" id="lastName" [(ngModel)]="newUser.lastName" required>
      </div>
    </div>

    <!-- ignore some code -->

  </modal-body>
</modal>



Reference
[1] http://www.w3schools.com/cssref/pr_padding-left.asp

2017/02/06

[Angular2] Dynamic Dropdown List

Problem
We have a dropdown list in the modal dialog:


The code snippet regarding dropdown list looks like:
    <div class="row">
      <div class="col-sm-10 form-inline">
        <label>電子郵件提醒事項</label>        
        <select class="form-control" id="mailNotification" [(ngModel)]="newUser.mailNotification">
            <option value="all">提醒與我的專案有關的全部事件</option>
            <option value="only_my_events">只提醒我觀察中或參與中的事物</option>
            <option value="only_assigned">只提醒我被分派的事物</option>
            <option value="only_owner">只提醒我作為擁有者的事物</option>
            <option value="none">取消提醒</option>
        </select>
      </div>
    </div>      

If I would like to use dynamic way to generate this dropdown list instead of static way, how to do it?

How-to
Step 1. declare an array which contains the texts and values in the dropdown list, and given a name 'mailNotifications'
import { Component } from '@angular/core';
import { CORE_DIRECTIVES } from '@angular/common';
import * as bootbox from 'bootbox';

@Component({
  selector: 'user-list',
  templateUrl: 'user.list.html'
})

export class UserComponent {

  searchUser: User = new User();
  newUser: User = new User();
  mailNotifications: Array<any> = [
    { text: '提醒與我的專案有關的全部事件', value: 'all' },
    { text: '只提醒我觀察中或參與中的事物', value: 'only_my_events' },
    { text: '只提醒我被分派的事物', value: 'only_assigned' },
    { text: '只提醒我作為擁有者的事物', value: 'only_owner' },
    { text: '取消提醒', value: 'none' }
  ];

  ngOnInit() {
    this.searchUser.status = 1;
  }

}



Step 2. Make good use of *ngFor to iterate its text and value for the dropdown list:
    <div class="row">
      <div class="col-sm-10 form-inline">
        <label>電子郵件提醒事項</label>
        <select class="form-control" id="mailNotification" [(ngModel)]="newUser.mailNotification">
           <option *ngFor="let n of mailNotifications" [ngValue]="n.value">{{n.text}}</option>
      </select>
      </div>
    </div>





2017/01/06

[Angular2] Services

Requirement
It's very common that multiple components may need access to the same code and we don't want to copy and paste the same code over and over. 
Therefore, we need create a single reusable data service and inject it in the components that need it.

How-To
(1) Create a service class looks like:
1
2
3
4
5
6
7
8
9
import { Injectable } from '@angular/core';
import { Http, Response, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class ProjectService {

  constructor(private http: Http) { }
}

(2) Import, register and initialize the service class in component class
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { Component, Pipe, PipeTransform } from '@angular/core';
import { CORE_DIRECTIVES } from '@angular/common';
import { TAB_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';
import { Router } from '@angular/router';
// import ProjectService
import { ProjectService } from './project.service';
import { MODAL_DIRECTIVES, ModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal';
import { PAGINATION_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';
import { StatusPipe } from './project.pipe';

@Component({
  selector: 'project-list',
  templateUrl: 'project.list.html',
  directives: [MODAL_DIRECTIVES, PAGINATION_DIRECTIVES],
  providers: [ProjectService], // register ProjectService to providers
  pipes: [StatusPipe]
})

export class ProjectComponent {
  
  // initialize ProjectService in constructor
  constructor(private projectService: ProjectService) {

  }
}

(3) If I add a search method in ProjectService:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import { Injectable } from '@angular/core';
import { Http, Response, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class ProjectService {

  constructor(private http: Http) { }
  
  search(searchProject: Project, page: number) {
    let name: string = searchProject.name;
    let status: number = searchProject.status;
    return this.http.get('/api/projects/search?name=' + name + '&status=' + status + '&page=' + page)
                    .map(res => <Page<Project>>res.json());
  }
}

(4) The component class code snippet looks like:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { Component, Pipe, PipeTransform } from '@angular/core';
import { CORE_DIRECTIVES } from '@angular/common';
import { TAB_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';
import { Router } from '@angular/router';
// import ProjectService
import { ProjectService } from './project.service';
import { MODAL_DIRECTIVES, ModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal';
import { PAGINATION_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';
import { StatusPipe } from './project.pipe';
import { Project, Page } from '../model/model';

@Component({
  selector: 'project-list',
  templateUrl: 'project.list.html',
  directives: [MODAL_DIRECTIVES, PAGINATION_DIRECTIVES],
  providers: [ProjectService], // register ProjectService to providers
  pipes: [StatusPipe]
})

export class ProjectComponent {
  
  projects: Page<Project>;
  
  // initialize ProjectService in constructor
  constructor(private projectService: ProjectService) {  }
  
  search() {
    this.projectService.search(this.searchProject, this.currentPage).subscribe(
          res => {
            this.projects = res;
          }
    );
  }

}



2017/01/05

[Angular2] Custom Pipe

Problem
I retrieve a collection of data with json data type, the json structure looks like:


These data will be displayed in data grid:


The second column displays status code, but I would like to display its description instead of code (i.e. 1:使用中、5:已關閉、9:已封存) :


How to do it?

How-To
Utilize custom pipe can solve this problem:

Step1. Create a custom pipe
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'statusPipe' })
export class StatusPipe implements PipeTransform {
  transform(status: number) {
    let statusName = '';
    if (status == 1) {
      statusName = '使用中';
    } else if (status == 5) {
      statusName = '已關閉';
    } else if (status == 9) {
      statusName = '已封存';
    }
    return statusName;
  }
}


Step2. Import custom pipe to your component. Here is the code snippet:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//...
import { StatusPipe } from './project.pipe';

@Component({
  selector: 'project-list',
  templateUrl: 'project.list.html',
  directives: [MODAL_DIRECTIVES, PAGINATION_DIRECTIVES],
  providers: [ProjectService],
  pipes: [StatusPipe]
})

export class ProjectComponent {

  searchProject: Project = new Project();
  projects: Page<Project>;

  constructor(private projectService: ProjectService, private appNotificationSerivce: AppNotificationService) {
  }
  //...
}  


Step3. Apply pipe to your html page. Here is the code snippet:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
  <div class="well" *ngIf="projects && projects.content.length > 0">
    <div class="table-responsive">
      <table class="table">
        <thead>
          <tr>
            <th width="70%">專案名稱</th>
            <th width="20% ">狀態</th>
            <th width="10% "></th>
          </tr>
        </thead>

        <tbody>
          <tr *ngFor="let project of projects.content; let rowIdx=i ndex ">
            <td> {{ project.name }}</td>
            <td> {{ project.status | statusPipe }}</td>
            <td> </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>



2017/01/03

[Angular2] Fail to install npm package

Problem
When I try to install npm package...
Command:
npm install -g angular-cli@webpack

I get this error message:
npm ERR! network If you are behind a proxy, please make sure that the
npm ERR! network 'proxy' config is set properly.  See: 'npm help config'
npm ERR! Please include the following file with any support request:

npm ERR!     C:\Users\chtti\npm-debug.log


How-to
The problem results from you don't configure proxy properly. Therefore, you need to set your corporate web proxy before you install npm package.
The command is as bellows:
npm config set proxy [your proxy]

Reference
[1] https://jjasonclark.com/how-to-setup-node-behind-web-proxy