เนื้อหานี้ เราจะมาดูต่อจากตอนที่แล้ว เกี่ยวกับการใช้งานฟอร์ม ซึ่งตอนที่แล้วเราได้พูดถึง
รูปแบบการส่งข้อมูลจากฟอร์มแบบต่างๆ สามารถกลับไปทบทวนได้ที่บทความ
ตามลิ้งค์ด้านล่าง
การส่งค่าจาก Form ด้วย ngModel FormBuilder และ Template ใน Ionic http://niik.in/866
https://www.ninenik.com/content.php?arti_id=866 via @ninenik
ซึ่งวิธีที่เราจะนำมาใช้ก็จะเป็นการใช้งาน ในส่วนของการส่งข้อมูลจากฟอร์มผ่าน FormBuilder ทั้งนี้ก็เพราะว่า
ส่วนของ FormBuilder เราสามารถปรับการตรวจสอบข้อมูลต่างๆ ของฟอร์มได้ง่ายและสะดวก มีเครื่องมือ
รองรับการจัดการที่ดี
การใช้งาน Form Validation
เพื่อให้เห็นภาพ เราจะสร้างหน้า page สำหรับสมัครสมาชิกขึ้นมาประกอบคำอธิบาย โดยให้เราทำการสร้าง page
ชื่อ signup ผ่าน ionic cli ด้วยคำสั่งดังนี้
ionic generate page signup --no-module
เราจะได้ไฟล์ signup.html signup.scss และ signup.ts จากนั้นกำหนดหน้าตาการแสดงของฟอร์มสำหรับสมัครสมาชิก
อย่างง่ายในไฟล์ signup.html ดังนี้
ไฟล์ signup.html
<ion-header> <ion-navbar color="secondary"> <button ion-button menuToggle> <ion-icon name="menu"></ion-icon> </button> <ion-title>Signup</ion-title> </ion-navbar> </ion-header> <ion-content padding> <div padding text-center> <h3>Create New User</h3> </div> <form [formGroup]="user" (ngSubmit)="doSignup()"> <ion-list> <ion-item> <ion-label floating>Username</ion-label> <ion-input type="text" formControlName="username"></ion-input> </ion-item> <ion-item> <ion-label floating>Password</ion-label> <ion-input type="password" formControlName="password"></ion-input> </ion-item> <ion-item> <ion-label floating>E-mail</ion-label> <ion-input type="email" formControlName="email"></ion-input> </ion-item> <ion-item> <ion-label floating>Phone</ion-label> <ion-input type="tel" formControlName="tel"></ion-input> </ion-item> </ion-list> <div> <button type="submit" [disabled]="!user.valid" block ion-button color="secondary">Sign Up</button> </div> </form> </ion-content>
ต่อด้วยโค้ดไฟล์ signup.ts เป็นดังนี้
ไฟล์ signup.ts
import { Component } from '@angular/core'; import { Validators, FormBuilder, FormGroup } from '@angular/forms'; import { NavController, NavParams } from 'ionic-angular'; @Component({ selector: 'page-signup', templateUrl: 'signup.html', }) export class SignupPage { public user:FormGroup; constructor( public navCtrl: NavController, public navParams: NavParams, public formBuilder: FormBuilder ) { this.user = this.formBuilder.group({ username: ['', Validators.required], password: ['',Validators.required], email: [''], tel: [''] }); } ionViewDidLoad() { console.log('ionViewDidLoad SignupPage'); } doSignup(){ console.log(this.user.value); console.log(this.user.valid); } }
ทดสอบการแสดง เริ่มต้นจะได้ดังรรูปผลลัพธ์ด้านล่าง
จะเห็นว่าในส่วนของ page component เรามีการใช้งาน FormBuilder ในการจัดการข้อมูลในฟอร์ม รวมถึงการ
ตรวจสอบค่าของข้อมูล โดยในตัวอย่าง เรามีการใช้งาน validators กำหนดให้ username และ password นั้นเป็น
ค่าที่จำเป็นต้องกรอก มิฉะนั้น ตัวแปร user ซึ่งเป็น FormGroup จะเป็น invalid หรือไม่ผ่านการตรวจสอบ อย่างใน
รูปแรก ยังไม่มีการกรอกข้อมูลใดๆ ปุ่ม SignUp ก็จะยังกดไม่ได้ เพราะฟอร์มยังไม่ผ่านการตรวจสอบข้อมูล เนื่องจาก
ยังไม่ได้กรอกข้อมูลใดๆ ลงไป และรูปที่สอง ฟอร์มก็ไม่ผ่านการตรวจสอบเพราะ ไม่ได้กรอกส่วนของ password ซึ่ง
เราได้กำหนดการ validator ไว้ว่า จำเป็นต้องกรอกด้วยการกำหนดค่า Validators.required
ทีนี้เรากรอกข้อมูลให้ครบถ้วน ก็จะทำให้สามารถกดปุ่ม SignUp ได้แล้ว ดังรูปด้านล่าง
เรามาพูดถึงเรื่องการตรวจสอบข้อมูลใน Angular ในรูปแบบการใช้งานฟอร์มแบบ Reactive Form เพื่อทบทวนกันเล็กน้อย
โดยอ้างอิงในส่วนของการใช้งานใน ionic
สมมติ user เป็นตัวแปร FormGroup ที่ตรวจสอบเฉพาะส่วนของ username เป็นดังนี้
this.user = this.formBuilder.group({ username: ['', Validators.required] });
ส่วนของ username เป็น formControl ที่มีการกำหนดค่าเริ่มต้นเป็นค่าว่าง ใน parameter แรก และกำหนดการ validate
หรือการตรวจสอบข้อมูลด้วย validators ใน parameter ตัวที่สอง หรือเขียนให้เข้าใจเป็นดังนี้
this.user = this.formBuilder.group({ username: ['ค่าเริ่มต้น หรือตัวแปรค่าเริ่มต้น', รูปแบบการตรวจสอบข้อมูล, รูปแบบการตรวจสอบข้อมูลแบบ async] });
ในรูปแบบการกำหนด formControl เราสามารถกำหนดค่าเริ่มต้นให้กับ formControl ใน parameter แรก ซึ่งจำเป็น
ต้องกำหนดส่วนนี้เสมอ ส่วน parameter ที่สอง นั้นเราจะกำหนดหรือไม่ก็ได้ อย่าง username เรากำหนดว่า จำเป็นต้อง
กรอก เราก็ใช้ Validators.required ซึ่งเป็นรูปแบบ build-in validator class ที่ตรวจสอบว่าค่านี้จำเป็นต้องกรอก
ส่วน parameter ทีสาม เป็นการตรวจสอบแบบ async เช่น เช็คไปที่ server ผ่าน service api ว่าค่านี้ซ้ำกับค่าเดิมที่
มีอยู่แล้วหรือไม่ เป็นลักษณะการทำงานที่ต้องรอค่าสักพัก ซึ่งในตัวอย่างโค้ดของเรา ไม่ได้ใช้งานในส่วนนี้
นอกจาก Validators.required แล้ว ยังมี Built-in validators เพิ่มเติม ที่สามารถนำมาใช้งานได้ทันทีเช่น
- Validators.min(18) // เป็นตัวเลข >=18
- Validators.max(40) // เป็นตัวเลข <=40
- Validators.email // มีรูปแบบ email ที่ถูกต้อง
- Validators.minLength(6) // กรอกข้อมูลความยาวอย่างน้อย 6 ตัวอักษร
- Validators.maxLength(15) // กรอกข้อมูลความยาวไม่เกิน 15 ตัวอักษร
- Validators.pattern(regx) // ตรวจสอบ รูปแบบ Regular expression
หรือสามารถกำหนดตามรูปแบบโครงสร้างของ class Validators ด้านล่าง
class Validators { static min(min: number): ValidatorFn static max(max: number): ValidatorFn static required(control: AbstractControl): ValidationErrors | null static requiredTrue(control: AbstractControl): ValidationErrors | null static email(control: AbstractControl): ValidationErrors | null static minLength(minLength: number): ValidatorFn static maxLength(maxLength: number): ValidatorFn static pattern(pattern: string | RegExp): ValidatorFn static nullValidator(c: AbstractControl): ValidationErrors | null static compose(validators: (ValidatorFn | null | undefined)[] | null): ValidatorFn | null static composeAsync(validators: (AsyncValidatorFn | null)[]): AsyncValidatorFn | null }
ดูรายละเอียดเพิ่มเติมได้ที่
โดยการกำหนด validator นั้นเราสามารถกำหนดหลายๆ เงื่อนไขเข้าไปได้ เช่น ต้องกรอก username ความยาว
ตั้งแต่ 6 ตัว แต่ไม่เกิน 15 ตัว ก็สามารถกำหนดเป็น
this.user = this.formBuilder.group({ username: ['', [ Validators.required, Validators.minLength(6), Validators.maxLength(15) ] ] });
ดูผลลัพธ์ตามรูปด้านล่าง
รูปแรก หมายถึงเรากรอกข้อมูล username แล้ว แต่เรายังไม่ผ่านเงื่อนไขว่า ขนาดความยาวของข้อมูล เราจึงไม่สามารถ
กดปุ่ม SignUp ได้ ในขณะที่รูปที่สอง เรากรอกข้อมูลเพิ่มเข้าไปเพื่อให้ username ครบ 6 ตัว ซึ่งผ่านเงื่อนไข
การตรวจสอบทำให้ปุ่ม SignUp สามารถกดได้นั่นเอง
เรามาปรับในส่วนของฟอร์มสมัครสมาชิกของเรา ให้มีการตรวจสอบข้อมูล โดยจะทำการตรวจสอบความถูกต้อง
ของข้อมูลทั้งหมด ให้ปรับไฟล์ signup.ts เป็นดังนี้
ไฟล์ signup.ts (เฉพาะส่วนของการตรวจสอบข้อมูล)
this.user = this.formBuilder.group({ username: ['', [ Validators.required, Validators.minLength(6), Validators.maxLength(15) ] ], password: ['', [ Validators.required, Validators.minLength(8), Validators.maxLength(20) ] ], email: ['',Validators.email], tel: ['',Validators.pattern('(^0)([1-9]){8}([0-9])$')] });
ขออธิบายเพิ่มเติมส่วนของ การใช้งาน pattern จะเห็นว่า สมมติว่า pattern ของเราเป็น '/(^0)([1-9]){8}([0-9])$/'
ก่อนนำไปใช้งาน ให้เราตัดส่วนของ / ออกให้เหลือเป็น '(^0)([1-9]){8}([0-9])$'
ทดสอบผลลัพธ์กรณีไม่ผ่านการตรวจสอบและผ่านการตรวจสอบความถูกต้องของข้อมูล
รูปแรกเรากรอกส่วนของ email และ phone ไม่ถูกต้องตามรูปแบบการตรวจสอบ ก็จะไม่สามารถกดปุ่ม SignUp ได้
ส่วนรูปที่สอง เราแก้ไขข้อมูล และกรอกใหม่ให้ถูกต้อง ก็จะสามารถกดปุ่ม SignUp เพื่อส่งข้อมูลได้
สังเกตว่า ส่วนของ email และ tel นั้น ถึงแม้เราไม่ได้กำหนด Validators.required เพื่อให้ผู้ใช้จำเป็นต้องกรอกข้อมูลนี้
แต่ด้วยรูปแบบเงื่อนไข ทำให้หากข้อมูลทั้งสองส่วนไม่มีค่าใดๆ หรือเป็นค่าว่าง ก็จะทำให้ การตรวจสอบข้อมูลไม่ผ่าน
ดังนั้น จึงต้องกรอกข้อมูลทั้งสองส่วนนี้และต้องให้ผ่านเงื่อนไขด้วย จึงจะทำการกดปุ่มส่งข้อมูล SignUp ได้
การใช้งาน Form Validation แบบกำหนดเอง
เราได้รู้จักการใช้งาน Form Validator จาก Buid-in validator ซึ่งอาจจะมีบางครั้ง เงื่อนไขที่ใช้ในการตรวจสอบ
มีมากกว่านั้น หรือแบบ build-in อาจจะไม่ใช่ในแบบที่ต้องการ เราสามารถทำการสร้าง validator ขึ้นมาใช้งานเองได้
อย่างสมมติเช่น เราต้องการให้ username เป็นตัวอักษรภาษาอังกฤษหรือตัวเลข และสัญลักษณ์พิเศษบางตัวเท่านั้น
วิธีการให้เราทำการสร้างโฟลเดอร์ชื่อ validators ตำแหน่ง path เดียวกันกับ app หรือ page ดังรูปด้านล่าง
จากนั้นให้สร้างไฟล์ด้านในชื่อ signupvalidator.ts กำหนดโค้ดเป็นดังนี้
ไฟล์ signupvalidator.ts
import { FormControl } from '@angular/forms'; export class SignupValidator { static checkUsername(control: FormControl): any { if(control.value.length >=6 && control.value.length<=15){ let pattern = new RegExp('(^[a-zA-Z0-9])+([a-zA-Z0-9._-])*(^\s)*([a-zA-Z0-9]+)$'); if (pattern.test(control.value)) { return null; } else { return { "username invalid":true } } }else{ return { "username length between 6 - 15 charactor":true } } } }
โดยในการสร้าง validator ฟังก์ชั่นไว้ใช้เองนั้น เราจะมีการใช้งาน FormControl จึงต้องทำการ import เข้ามาใช้งาน
ข้างต้น เราสร้างเป็นแบบ class ชื่อ SignupValidator และกำหนดฟังก์ชั่นชื่อ checkUsername เป็นแบบ static ทำ
ให้สามารถเรียกใช้งานในรูปแบบ SignupValidator.checkUsername ได้ เพื่อจะได้ไปใช้กำหนดในหน้าตรวจสอบ
โดยฟังก์ชั่น checkUsername จะมีการใช้งาน formControl ที่ถูกเรียกใช้จากฟังก์ชั่นนี้ อย่างในตัวอย่าง
เราจะใช้กับ username formControl ที่ถูกส่งเข้ามา ก็จะเป็นส่วนของ username ซึ่งเราสามารถอ้างอิงค่าได้ผ่าน control.value
สำหรับการทำ validator นั้น เราจะทำการคืนค่ากลับไปใน 2 รูปแบบคือ เป็น null ถ้าไม่ติดเงื่อนไขการตรวจสอบใดๆ
และเป็น Object ที่มี key เป็นข้อความระบุเงื่อนไขที่ไม่ผ่าน พร้อมมีค่า value เป็น true
อย่างในตัวอย่าง ถ้าไม่เข้าเงื่อนไขแรกการเช็คขนาดความยาว ก็ไปทำในส่วน else และคืนค่า object เป็น
{ "username length between 6 - 15 charactor":true }
และเงื่อนไขทีสอง ถ้าข้อความเข้าเงื่อนไข regular expression pattern ก็จะ return null คือไม่ติดเงื่อนไขใดๆ
แต่ถ้าไม่ผ่านการตรวจสอบรูปแบบ ก็จะ คืนค่า object เป็น
{ "username invalid":true }
ค่า 'username length between 6 - 15 charactor' และ 'username invalid' นั้นเป็นค่า key ที่เรากำหนดเอง ควร
ใช้เป็นภาษาอังกฤษ สื่อให้ชัดเจน
การนำไปใช้งาน ก็ให้เราทำการ import SignupValidator ไปใช้งานในหน้าฟอร์ม พร้อมเรียกใช้ในการของการตรวจสอบ
ฟอร์มดังนี้
ไฟล์ signup.ts
import { Component } from '@angular/core'; import { Validators, FormBuilder, FormGroup } from '@angular/forms'; import { NavController, NavParams } from 'ionic-angular'; import { SignupValidator } from '../../validators/signupvalidator'; @Component({ selector: 'page-signup', templateUrl: 'signup.html', }) export class SignupPage { public user:FormGroup; constructor( public navCtrl: NavController, public navParams: NavParams, public formBuilder: FormBuilder ) { this.user = this.formBuilder.group({ username: ['', [ Validators.required, SignupValidator.checkUsername ] ], password: ['', [ Validators.required, Validators.minLength(8), Validators.maxLength(20) ] ], email: ['',Validators.email], tel: ['',Validators.pattern('(^0)([1-9]){8}([0-9])$')] }); } ionViewDidLoad() { console.log('ionViewDidLoad SignupPage'); } doSignup(){ console.log(this.user); console.log(this.user.value); console.log(this.user.valid); } }
บรรทัดที่ 5 import SignupValidator มาใช้งาน และ
บรรทัดที่ 22 เรียกใช้งาน คล้ายๆ กับการเรียกใช้งาน Build-in validator
ดูตัวอย่างผลลัพธ์การเรียกใช้งาน
รูปแรกเรากรอก username เป็นภาษาไทย จึงไม่ผ่านรูปแบบการตรวจสอบความถูกต้อง รูปที่สองเรากรอก
ข้อมูล username ให้ถูกต้องตามรูปแบบเงื่อนไข จึงสามารถกดปุ่ม SignUp เพื่อส่งค่าไปใช้งานต่อได้
การกำหนด Validation แบบ Async
การตรวจสอบข้อมูลแบบ async นั้นก็เหมือนกับการส่งข้อมูลแบบ ajax ที่เมื่อส่งค่าไปทำงานแล้ว ก็อาจจะต้องรอสัก
พักเพื่อรับค่าข้อมูลที่ส่งกลับมา หรือเข้าใจง่ายๆ ก็คือการทำงานที่ไม่ได้เกิดขึ้นพร้อมกันในทันที
อย่างที่เราบอกไปในตอนต้นว่า การตรวจสอบฟอร์มด้วย validator นั้น เราสามารถกำหนดฟังก์ชั่นสำหรับตรวจสอบ
โดยกำหนดในส่วนของ parameter ตัวที่ 3 ของการใช้งาน formControl ในที่นี้ เราจะทำตัวอย่างแบบไปเช็คค่าข้อมูล
ของ username ที่อยู่บน server จำลอง ผ่าน service api อย่างง่าย จากนั้นนำค่าที่ได้ ไปเป็นเงื่อนไขในการสร้าง
ฟังก์ชั่นตรวจสอบข้อมูลแบบ async อีกที
ให้เตรียมส่วนของ service api ฝั่ง server อย่างง่ายกันก่อน ให้เราสร้างตารางบน server จำลอง
ตามรูปแบบโครงสร้างคำสั่ง sql ดังนี้
-- -- Table structure for table `tbl_user` -- CREATE TABLE `tbl_user` ( `userID` int(11) NOT NULL, `userName` varchar(100) NOT NULL, `userPass` varchar(255) NOT NULL, `userEmail` varchar(100) NOT NULL, `userTel` varchar(13) NOT NULL, `userCreateDate` datetime NOT NULL, `userActive` tinyint(1) NOT NULL, `userToken` varchar(250) NOT NULL, `userTokenExpire` datetime NOT NULL, `userLastAccess` datetime NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Indexes for dumped tables -- -- -- Indexes for table `tbl_user` -- ALTER TABLE `tbl_user` ADD PRIMARY KEY (`userID`), ADD UNIQUE KEY `userName` (`userName`,`userEmail`,`userTel`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `tbl_user` -- ALTER TABLE `tbl_user` MODIFY `userID` int(11) NOT NULL AUTO_INCREMENT;
จากนั้นให้ทำการเพิ่มข้อมูลเข้าไปคร่าวๆ เฉพาะในส่วนของ userName กับ userPass เป็นดังนี้
ต่อไปสร้างไฟล์ service api อย่างง่ายตามนี้
ไฟล์ dbconnect.php
<?php $mysqli = new mysqli("localhost", "root","","test"); /* check connection */ if ($mysqli->connect_errno) { printf("Connect failed: %s\n", $mysqli->connect_error); exit(); } if(!$mysqli->set_charset("utf8")) { printf("Error loading character set utf8: %s\n", $mysqli->error); exit(); }
ไฟล์ validator.php
<?php header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Headers: Content-Type,X-Custom-Header'); header('Content-type: application/json'); require_once("dbconnect.php"); $jsonData = array(); if($_SERVER['REQUEST_METHOD'] == "GET") { echo json_encode($jsonData); }elseif($_SERVER['REQUEST_METHOD'] == "OPTIONS"){ echo json_encode($jsonData); }elseif($_SERVER['REQUEST_METHOD'] == "POST"){ $json = file_get_contents('php://input'); $postData = json_decode($json, TRUE); $sql = " SELECT userID FROM tbl_user WHERE userName='".$postData['username']."' "; $result = $mysqli->query($sql); if($result && $result->num_rows>0){ // คิวรี่ข้อมูลสำเร็จหรือไม่ และมีรายการข้อมูลหรือไม่ echo json_encode(array( "statusCode"=>true, "statusMessage"=>"Username Taken" )); }else{ echo json_encode(array( "statusCode"=>false, "statusMessage"=>"Username Available" )); } }else{ header("HTTP/1.1 403 Access Forbidden"); echo json_encode(array( "statusCode"=>"403 Access Forbidden", "statusMessage"=>"Fail" )); } ?>
ส่วนของไฟล์ service api ของเราจะเป็นรูปแบบการทำงานอย่างง่ายคือ รอรับค่าตัวแปร username แล้วนำ
ค่าไปตรวจสอบในฐานข้อมูล ถ้ามีการใช้ชื่อนี้แล้ว ก็ให้ส่ง json string กลับมายัง app โดยในที่นี้้เราจะใช้
statusCode เป็นตัวหลักในการตรวจสอบ โดยถ้าส่งกลับเป็น true หมายถึง username นี้ถูกใช้แล้ว และเป็น
false กรณียังว่างอยู่
ต่อไปให้เราทำการสร้าง service provider ที่จะทำการส่งค่าข้อมูล username ไปยังไฟล์ service api โดยสร้างด้วย
ionic cli ดังนี้
ionic generate provider validator
เราจะได้ไฟล์ validator.ts อยู่ในโฟลเดอร์ providers > validiator จากนั้นให้สร้างฟังก์ชั่นส่งค่า username ไปตรวจสอบ
ที่ service api เป็นดังนี้
ไฟล์ validator.ts
import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable() export class ValidatorProvider { public urlApi:string = "http://localhost/demo/"; constructor(public http: HttpClient) { console.log('Hello ValidatorProvider Provider'); } checkexistUsername(username:any){ let data = { username:username } return this.http.post(this.urlApi+'validator.php',data); } }
ฟังก์ชั่น checkexistUsername() จะส่ง username ที่เรากรอกส่งไปยังไฟล์ validator.php ซึ่งเป็น service api
เพื่อตรวจสอบค่า username นั้นๆ ว่ายังว่างหรือไม่ และส่งกลับข้อมูลมาในรูปแบบ json string data ที่มี
ค่า statusCode และ statusMessage โดยเป็นข้อมูลประเภท Observable
ในฟังก์ชั่นนี้ เราจะยังไม่มีการดึงค่าข้อมูลออกมาใช้งาน จึงไม่มีการกำหนด subscribe() ให้กับ Observable
เราจะไปเรียกใช้ค่าอีกทีในไฟล์ที่ใช้งาน
หมายเหตุ: อย่าลืมว่าเมื่อใดที่เรามีการใช้งาน HttpClient เราต้องทำการ import HttpClientModule มาใช้งานใน
AppModule ในไฟล์ app.module.ts ก่อนเสมอ สามารถทบทวนได้ที่ลิ้งค์ด้านล่าง
การดึงข้อมูลจาก Service API ด้วย HttpClient ใน ionic เบื้องต้น http://niik.in/863
https://www.ninenik.com/content.php?arti_id=863 via @ninenik
กลับมาในส่วนของไฟล์ฟังก์ชั่น ที่เราสร้างเงื่อนไขการตรวจสอบเข้ามาใช้งานเองตามหัวข้อที่ผานมา ชื่อไฟล์
signupvalidator.ts เราได้สร้าง validator ฟังก์ชั่นชื่อ checkUsername ขึ้นมาใช้งาน ซึ่งเป็นการตรวจสอบแบบ sync
ต่อไปเราจะเพิ่มฟังก์ชั่นการตรวจสอบแบบ async เข้าไปชื่อว่า checkUsernameExist
ขอยกโค้ดไฟล์ signupvalidator.ts ที่ปรับเรียบร้อยแล้วมาประกอบคำอธิบาย
ไฟล์ signupvalidator.ts
import { FormControl } from '@angular/forms'; import { ValidatorProvider } from '../providers/validator/validator'; // สร้าง interface ของข้อมูลที่จะ return กลับมาให้สอดคล้องกัน เพื่ออ้างอิง interface ResponseData { statusCode: boolean, statusMessage: string } export class SignupValidator { // ฟังก์ชั่น checkUsernameExist ที่เราเพิ่มมาเพื่อใช้งานแบบ async static checkUsernameExist(validUser: ValidatorProvider) { return (control: FormControl) => { return new Promise(resolve => { validUser.checkexistUsername(control.value) .subscribe((res: ResponseData) => { if (res.statusCode) { resolve({ 'Username Taken': true }); } else { resolve(null); } }); }); }; } static checkUsername(control: FormControl): any { if (control.value.length >= 6 && control.value.length <= 15) { let pattern = new RegExp('(^[a-zA-Z0-9])+([a-zA-Z0-9._-])*(^\s)*([a-zA-Z0-9]+)$'); if (pattern.test(control.value)) { return null; } else { return { "username invalid": true } } } else { return { "username length between 6 - 15 charactor": true } } } }
บรรทดัที่ 2 เรา import ValidatorProvider เข้ามาใช้งาน เพราะเราจะส่งค่าไปยัง service api
ผ่าน ValidatorProvider
บรรทัดที่ 5 - 8 เป็นการกำหนดหน้าตาของข้อมูลที่จะ return กลับมาจาก service api ทั้งนี้
เพื่อให้เวลาอ้างอิงข้อมูลสามารถทำได้ง่ายและมีความถูกต้อง
บรรทัดที่ 13 - 29 เป็นฟังก์ชั่นสำหรับ validator แบบ async เพราะมีการส่งค่าไปยัง service api และรอรับค่า
ที่จะส่งกลับมาก่อนนำไปใช้งาน ฟังก์ชั่น checkUsernameExist เราจะส่ง ValidatorProvider เป็น parameter
เข้ามา เพื่อไปเรียกใช้ฟังก์ชั่น checkexistUsername() ด้านในอีกที
ฟังก์ชั่น checkUsernameExist จะทำการ return รูปแบบข้อมูลแบบ validator กลับออกมา โดยใช้รูปแบบการ
ส่งข้อมูลกลับมาแบบ ajax ที่เรียกว่า Promise() object โดยใน Promise() เราก็ใช้ ValidatorProvider ไปดึง
ข้อมูลฝั่ง service api ออกมาโดยเรียกใช้คำสั่ง subscribe() เมื่อได้ข้อมูลกลับมาแล้ว เราก็ตรวจสอบค่า
โดยถ้าค่า statusCode เป็น true ก็หมายถึงว่า ชื่อนี้ไม่ว่างแล้ว เราก็จะใช้ resole() ของ promise() object ส่ง
ค่า validator กลับออกมา
{ 'Username Taken': true }
หรือถ้ากรณีเป็น false ก็หมายความว่าชื่อนี้ยังว่าง สามารถใช้งานได้ ก็จะ return null กลับออกมา
เนื่องจากมีการซ้อนกันของรูปแบบการใช้งาน อาจจะงงได้ ยังไงลองไล่ดูการทำงานแบบทบทวนกันบ่อยๆ
หรือให้เข้าใจอย่างง่ายคือ ValidatorProvider เรียกฟังก์ชั่น checkexistUsername ไปตรวจสอบข้อมูลใน
service api ที่ server พอได้ค่ากลับมา ก็เอาค่าที่ได้มาเป็นเงื่อนไขการกำหนดรูปแบบ ข้อมูล validator โดย
ใช้ resolve() ทำส่งข้อมูลออกมาในรูปแบบ Promise() object แล้วก็ค่อย return ค่าออกไปใช้งานอีกที
สุดท้ายก็เป็นส่วนของการใช้งาน Validation แบบ Async ที่เราสร้างขึ้น โดยเราจะมากำหนดใช้งานเพิ่มเข้าไปใน
ไฟล์ signup.ts เป็นดังนี้
ไฟล์ signup.ts
import { Component } from '@angular/core'; import { Validators, FormBuilder, FormGroup } from '@angular/forms'; import { NavController, NavParams } from 'ionic-angular'; import { SignupValidator } from '../../validators/signupvalidator'; import { ValidatorProvider } from '../../providers/validator/validator'; @Component({ selector: 'page-signup', templateUrl: 'signup.html', }) export class SignupPage { public user:FormGroup; constructor( public navCtrl: NavController, public navParams: NavParams, public validService:ValidatorProvider, public formBuilder: FormBuilder ) { this.user = this.formBuilder.group({ username: ['', [ Validators.required, SignupValidator.checkUsername ], SignupValidator.checkUsernameExist(this.validService) ], password: ['', [ Validators.required, Validators.minLength(8), Validators.maxLength(20) ] ], email: ['',Validators.email], tel: ['',Validators.pattern('(^0)([1-9]){8}([0-9])$')] }); } ionViewDidLoad() { console.log('ionViewDidLoad SignupPage'); } doSignup(){ console.log(this.user); console.log(this.user.value); console.log(this.user.valid); } }
บรรทัดที่ 5 - 6 เรา import SignupValidator และ ValidatorProvider เข้ามาใช้งาน
และเนื่องจาก เรามีการใช้งาน ValidatorProvider service เราต้องทำการ inject เข้ามาใช้
ตามบรรทัดที่ 18 โดยอ้างอิงด้วยชื่อตัวแปร validService
ต่อไปส่วนอื่นๆ ก็แทบเหมือนเติม ให้ดูเฉพาะบรรทัดที่เกี่ยวกับ การกำหนด username
username: ['', [ Validators.required, SignupValidator.checkUsername ], SignupValidator.checkUsernameExist(this.validService) ],
เรามีการใช้งาน Validators.required ซึ่งเป็น Build-in validator และ
SignupValidator.checkUsername ซึ่งเป็น validator ที่เราสร้างขึ้นมาใช้งานในรูปแบบ sync
ในส่วนของ parameter ที่สองของ username formControl
และมีการใช้งาน SignupValidator.checkUsernameExist(this.validService) ซึ่งเป็น validator ที่เราสร้างขึ้นมาใช้งาน
ในรูปแบบ async โดยฟังก์ชั่น checkUsernameExist มีการส่ง this.validService เข้าไปใช้งาน ตามรูปแบบ
ฟังก์ชั่นที่เราสร้าง
เราจะมาทดสอบดูผลลัพธ์การดู ตามที่เราได้เพิ่ม username ที่ชื่อ demo56 ลงไปในฐานข้อมูลแล้ว ซึ่งถ้าเรากรอก
ชื่อนี้ ก็จะไม่ผ่านการตรวจสอบฟอร์ม เพราะชื่อซ้ำ ตามรูปผลลัพธ์แรก และเราลองเปลี่ยน username โดยเพิ่มเลย 7 ต่อท้าย
ลงไป ก็จะทำให้ผ่านการตรวจสอบ เพราะไม่มีชื่อนี้ในระบบ เท่านี้เราก็สามารถส่งข้อมูลที่ผ่านการตรวจสอบแล้วไปใช้งานได้
ในเนื้อหานี้ เราได้ศึกษาการใช้งาน การตรวจสอบฟอร์มที่ค่อนข้างละเอียด และสามารถไปประยุก์ปรับแต่งเพิ่มเติมได้
ตามความเหมาะสม แต่อย่างไรก็ตาม การตรวจสอบในส่วนของ javascript นี้ เป็นรูปแบบการกำหนดที่เพื่อให้ผู้ใช้ ได้รับ
ประสบการณ์ในการใช้ที่ดีงานมากกว่า ส่วนการป้องกันหรือตรวจสอบความถูกต้องของข้อมูลโดยตรง และเพื่อความปลอดภัย
เราจำเป็นที่จะต้องมีการตรวจสอบความถูกต้องของข้อมูลอีกครั้งในฝั่ง server ก่อนนำค่าไปใช้งาน
เนื้อหาตอนหน้าจะเป็นอะไร โปรดรอติดตาม