实战对象:股票列表展示和修改表单,前端采用angular,后端采用php
第一步:后端代码实现【angular/index.php】:获取数据
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
$type=$_GET['type'];
$id=$_GET['id'];
$stocks=[
['id'=>1,'name'=>"第一支股票",'price'=>1.99,'rating'=>3.5,'desc'=>"這是第一隻股票呵呵噠",'categories'=>["金融","互聯網"]],
['id'=>2,'name'=>"第二支股票",'price'=>2.99,'rating'=>2.5,'desc'=>"這是第二隻股票呵呵噠",'categories'=>["金融","互聯網"]],
['id'=>3,'name'=>"第三支股票",'price'=>3.99,'rating'=>3,'desc'=>"這是第三隻股票呵呵噠",'categories'=>["金融","IT"]],
['id'=>4,'name'=>"第四支股票",'price'=>4.99,'rating'=>2,'desc'=>"這是第四隻股票呵呵噠",'categories'=>["互聯網"]],
];
function getStocks($stocks,$type,$id){
if(empty($type)){
echo json_encode(['state'=>0,'msg'=>'请求路径错误,没有type参数']);
}
if($type=="list"){
echo json_encode($stocks);
}else if($type=="form"){
for($i=0;$i<count($stocks);$i++){
if($stocks[$i]['id']==$id){
echo json_encode($stocks[$i]);
break;
}
}
}
}
getStocks($stocks,$type,$id);
?>
第二步:前端在服务【stock.service.ts】中发送http请求,获取数据
import { Injectable } from '@angular/core';
import { Http,Response } from '@angular/http';
import { Observable } from 'rxjs';
@Injectable()
export class StockService {
private stocks:Observable<Object>;
constructor(private http:Http) { }
//获取列表数据
getStocks():Observable<Stock[]>{
return this.http.get("http://localhost/angular/index.php?type=list").map(res=>res.json());
}
//获取单个表单数据
getStock(id:number):Observable<Stock> {
return this.http.get("http://localhost/angular/index.php?type=form&id="+id).map(res=>res.json());
}
}
export class Stock{
constructor(
public id:number,
public name:string,
public price:number,
public rating:number,
public desc:string,
public categories:Array<string>
){
}
}
第三步【##1】:在列表组件【stock-manage.component.ts】获取服务中获取的数据
import {FormControl} from '@angular/forms';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { StockService, Stock } from '../../stock.service';
import 'rxjs/Rx';
import { Observable } from 'rxjs';
@Component({
selector: 'app-stock-manage',
templateUrl: './stock-manage.component.html',
styleUrls: ['./stock-manage.component.css']
})
export class StockManageComponent implements OnInit {
private stocks:Observable<Stock[]>;//定义一个变量,接收流类型的数据,且知此处使用的是异步管道处理返回的流数据
constructor(private stockService:StockService) { }
ngOnInit() { //頁面初始化的時候會被調用的方法
this.stocks=this.stockService.getStocks(); //此处调用服务中的数据
}
}
第三步【##2】:在列表组件模板【stock-manage.component.html】中用异步管道处理流数据
<table class="table table-bordered">
<tr>
<th>#</th>
<th >股票名称</th>
<th>价格</th>
<th>评级</th>
<th >操作</th>
</tr>
<tr *ngFor="let stock of stocks | async|stockFilter:'name':keyword;let i=index">
<td>{{i+1}}</td>
<td>{{stock.name}}</td>
<td>{{stock.price}}</td>
<td>
<app-stars [rating]="stock.rating"></app-stars>
</td>
<td>
<a class="btn btn-warning btn-xs" href="javascript:;" (click)="update(stock)" >
<span class="glyphicon glyphicon-pencil"></span>修改</a>
<a class="btn btn-danger btn-xs" href="#"><span class="glyphicon glyphicon-remove"></span>删除</a>
</td>
</tr>
</table>
第四步【##1】:修改表单组件中【stock-form.component.ts】获取服务的数据
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { StockService, Stock } from '../../stock.service';
import { FormGroup, FormBuilder, Validators, FormControl, FormArray } from '@angular/forms';
@Component({
selector: 'app-stock-form',
templateUrl: './stock-form.component.html',
styleUrls: ['./stock-form.component.css']
})
export class StockFormComponent implements OnInit {
public stock=new Stock(0,"",0,0,"",[]); //初始化表单对象,用以等待http请求返回结果,以免报错
constructor(private routerinfo:ActivatedRoute,private stockService:StockService,private router:Router) { }
//创建表单模型对象,让angular来接管表单处理
private formModel:FormGroup; //并且要将当前这个属性绑定到模板中form标签的[formGroup]指令上
private categories=["IT","互聯網",'金融']; //股票类型初始化,原始数据,并将其绑定到模板
ngOnInit() {
let stockid=this.routerinfo.snapshot.params["id"];
//声明数据结构
let fb=new FormBuilder();
this.formModel=fb.group({
name:['',[Validators.required,Validators.minLength(3)]],
//将name绑定到模板页面的formControlName上:formControlName="name"
price:['',Validators.required],
desc:[''],
categories:fb.array([ //用法原因:股票的类型在定义的时候就是string的数组Array<string>,[true,true,null]
//this.stock.categories.indexOf(this.categories[0])!=-1 this.stock.categories里面有IT就返回true
new FormControl(false),
new FormControl(false),
new FormControl(false),
],this.categoriesSelectValidator)
});
if(stockid!=0){
this.stockService.getStock(stockid).subscribe(
data=>{
this.stock=data;
console.log(data);
this.formModel.reset({
name:data.name,
price:data.price,
desc:data.desc,
categories:[
data.categories.indexOf(this.categories[0])!=-1,
data.categories.indexOf(this.categories[1])!=-1,
data.categories.indexOf(this.categories[2])!=-1,
]
})
}
);
}else{
this.stock=new Stock(0,"",0,0,"",[]);
}
}
save(){
//1.rating的处理,
this.formModel.value.rating=this.stock.rating;
//2 将股票类型转换为汉字
var categoriesChainese=[];
var index=0;
for(var i=0;i<3;i++){
if(this.formModel.value.categories[i]){ //说明当前项被选中,就将其转为汉字
categoriesChainese[index++]=this.categories[i]
}
}
this.formModel.value.categories=categoriesChainese;
//打印出表单数据模型
console.log(this.formModel.value);
//this.router.navigate(['/stock']);
}
//股票类型校验器
categoriesSelectValidator(control:FormArray):any{
//
var valid=false;
control.controls.forEach(control=>{
if(control.value){
valid=true
}
});
if(valid){
return null;
}else{
return {categoriesLength:true};
}
}
}
第四步【##2】:修改表单组件中模板【stock-form.component.html】展示获取的数据,和原来一样不用修改
<p>
{{stock.name}}
</p>
<!-- Horizontal Form -->
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">股票信息</h3>
</div>
<!-- /.box-header -->
<!-- form start -->
<form class="form-horizontal" [formGroup]="formModel">
<div class="box-body">
<!-- ##校验name -->
<div class="form-group" [class.has-error]="formModel.get('name').touched &&
(formModel.hasError('minlength','name')||formModel.hasError('required','name'))">
<label for="name" class="col-sm-2 control-label">股票名称</label>
<div class="col-sm-6">
<input type="text" class="form-control" formControlName="name" id="name" placeholder="股票名称" >
</div>
<span class="help-block" [class.hidden]="formModel.get('name').untouched||
!formModel.hasError('required','name')" >股票名称是必填项!</span>
<span class="help-block" [class.hidden]="formModel.get('name').untouched||
!formModel.hasError('minlength','name')">股票名称长度至少3位!</span>
</div>
<!-- ##校验price -->
<div class="form-group" [class.has-error]="formModel.get('price').touched &&
formModel.hasError('required','price')">
<label for="price" class="col-sm-2 control-label" >股票价格</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="price" formControlName="price" placeholder="股票价格">
</div>
<span class="help-block" [class.hidden]="formModel.get('price').untouched||
!formModel.hasError('required','price')" >股票价格是必填项!</span>
</div>
<div class="form-group">
<label for="price" class="col-sm-2 control-label">股票评级</label>
<div class="col-sm-10">
<app-stars [(rating)]="stock.rating"></app-stars>
</div>
</div>
<div class="form-group">
<label for="price" class="col-sm-2 control-label" >股票描述</label>
<div class="col-sm-10">
<textarea class="form-control" formControlName="desc" placeholder="股票描述"></textarea>
</div>
</div>
<!-- ##校验categories 自定义校验器 -->
<!-- 【1】将整个checkbox组绑定到后台的categories -->
<div class="form-group" formArrayName="categories" [class.has-error]="formModel.get('categories').touched &&
formModel.hasError('categoriesLength','categories')" >
<label for="categories" class="col-sm-2 control-label" >股票类型</label>
<!-- 【2】循环初始化数组categories -->
<div *ngFor="let category of categories;let i=index;" class=" col-sm-2">
<div class="checkbox ">
<label>
<!-- 【3】将每个checkbox绑定到categories的每个项,因为是绑定到变量上所以加[formControlName] -->
<input [formControlName]='i' type="checkbox" > {{category}}
</label>
</div>
</div>
<span class="help-block" [class.hidden]="formModel.get('categories').untouched||
!formModel.hasError('categoriesLength','categories')" >请至少选择一个类型!</span>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<button type="submit" class="btn btn-default">取消</button>
<!-- 控制表单不合法时,保存按钮不可点击 -->
<button type="submit" [disabled]="formModel.invalid" class="btn btn-info pull-right" (click)="save()" >保存</button>
</div>
<!-- /.box-footer -->
</form>
</div>
<!-- /.box -->
页面效果分别为:
【1】股票列表
【2】股票修改