angularjs入門-$http and code first

angularjs入門-$http

建立DB的資料和預設內容

 

angularjs的$http其實本身就有很多東西可以說,比如像promises或$q甚至是專支援restful特性的ngresource,但這系列其實只是入門,我也並不打算在此篇能包山包海的去談,這系列入門其實只是希望給還不會angularjs的人,可以有一個入門的方向,所以不會涉獵太深,未來有機會再多寫一點記錄,但因為我們需要使用$http去呼叫web api,所以在這邊我打算先從web api和code first去建立一個後端來進行互動,首先我們先開起vs,然後選擇web api的方案,我這邊是vs2013,我直接就選擇web api專案,如下圖

 

image2

 

然後我想先把identity給取消掉,選擇Change Authentication,然後選擇No Authentication,接下按下ok

 

image5

 

接下來我先選擇nuget,然後下載EntityFramework還有angularjs

 

image11

 

 

接著我直接在Models新增一個students的類別,程式碼如下

 

image17

 

接著我在Models再新增一支DefaultContext的類別,程式碼如下

using System.Collections.Generic;   
using System.Data.Entity;   
  
namespace WebApiDemo.Models   
{   
    public class DefaultContext : DbContext   
    {   
        public DefaultContext()   
            : base("DefaultConnection")   
        {   
            Database.SetInitializer<DefaultContext>(new DefaultDataInit());   
        }   
  
        public DbSet<Student> Student { get; set; }   
    }   
}  

 

我在Models下又新增了一支DefaultDataInit.cs,因為我希望在顯示的時候,可以先在db塞點預設的資料,需要實作CreateDatabaseIfNotExists,這個則是代表如果沒有資料的話,會先建立預設的資料,程式碼如下

using System.Data.Entity;   
using System.Data.Entity.Migrations;   
  
namespace WebApiDemo.Models   
{   
    public class DefaultDataInit:CreateDatabaseIfNotExists<DefaultContext>   
    {   
        public override void InitializeDatabase(DefaultContext context)   
        {   
            base.InitializeDatabase(context);   
            context.Student.AddOrUpdate(x => x.Name,   
                    new Student() { Name = "王小明", PhoneNumber = "0915808888", Address = "台中市" },   
                    new Student() { Name = "王大明", PhoneNumber = "0915801111", Address = "台北市" },   
                    new Student() { Name = "王大雄", PhoneNumber = "0915806666", Address = "台南市" },   
                    new Student() { Name = "王小雄", PhoneNumber = "0915800000", Address = "新北市" },   
                    new Student() { Name = "王小安", PhoneNumber = "0915807777", Address = "桃園市" }   
                );   
            context.SaveChanges();   
        }   
    }   
}  

 

然後我們需要在web.config設定連線字串,我在此是用DefaultConnection,請把連線改成您自己的,我自己有建立另外一個執行個體,所以是MSSQL,預設則會是v11.0,這邊使用的是localdb方便本機測試,如下

<connectionStrings>   
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQL;Initial Catalog=AngularjsDB;Integrated Security=SSPI;" providerName="System.Data.SqlClient"/>   
</connectionStrings>  

 

接著請打開Package Manager Console

image35

 

 

然後首先輸入enable-migrations,第二個指令則是輸入add-migration init,最後是update-database,這時候我們就已經建立了db在您預設的位置

 

image41

 

 

 

建立Web API部份

 

 

在來就是WebApi的部份,我在這部份就是把預設的ValuesController改掉,下是就是簡單的示例

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebApiDemo.Models;

namespace WebApiDemo.Controllers
{
    public class ValuesController : ApiController
    {
        DefaultContext db = new DefaultContext();
        // GET api/values
        public IEnumerable<Student> Get()
        {
            return db.Student.ToList();
        }

        // POST api/values
        public Student Post(Student emp)
        {
            db.Student.Add(emp);
            db.SaveChanges();
            return emp;
        }

        // PUT api/values/5
        public void Put(Student emp)
        {
            db.Entry(emp).State = EntityState.Modified;
            db.SaveChanges();
        }

        // DELETE api/values/5
        public void Delete(int id)
        {
           var emp =db.Student.Find(id);
           db.Entry(emp).State = EntityState.Deleted;
           db.SaveChanges();
        }
    }
}

 

 

建立前端html和angularjs的部份

 

接下來就是把angularjs放進Views>Shared>_Layout.cshtml裡面,我把一些不需要的區塊和jquery等等拿掉,只留我想要的,如下圖

 

image23

 

接著我新加了App的資料夾,裡面新增一支Index.js,預計要來寫angularjs的程式碼,然後我就直接修改預設的HomeController的Index,程式碼如下

Home/Index.cshtml

<div class="row" ng-controller="FirstCtrl as firstCtrl">  
    <div ng-switch="View">  
        <div ng-switch-default>  
            <table class="table">  
                <tr>  
                    <th>姓名</th>  
                    <th>電話</th>  
                    <th>地址</th>  
                </tr>  
                <tr ng-repeat="item in firstCtrl.student">  
                    <td>{{item.Name}}</td>  
                    <td>{{item.PhoneNumber}}</td>  
                    <td>{{item.Address}}</td>  
                </tr>  
            </table>  
        </div>  
    </div>  
</div>  
@section scripts{   
<script src="~/App/Index.js"></script>  
}  

 

在這邊我先只做顯示的部份,之後會再加上新刪修的功能示範,接下來看一下index.js的程式碼

angular.module('MyApp', [])   
    .controller('FirstCtrl', function ($http) {   
        var Url = 'http://localhost:65414/Api/'  
        var vm = this;   
        $http.get(Url + 'Values').success(function (data) {   
            vm.Student = data;   
        }).error(function () {   
            alert('發生錯誤');   
        });   
    });  

 

請注意一下,因為我們需要用到$http,所以需要注入進來此controller

 

image50

 

Url是您自己的網址,$http.get則是angularjs的快捷指令,success的話之後回調的值不一定要全部填上,也可以只需要填寫data,也可以取名成自己想要的命名,然後error也就是發生錯誤的時候要做什麼處理,接著就是展現出來的畫面

 

image44

 

至此我們已經順利的從後端取資料顯示出來了

 

 

實做新增功能

 

我在html新增了兩顆按鈕,分別是新增和儲存,如下

Index.cshtml

<div class="row" ng-controller="FirstCtrl as firstCtrl">  
    <div class="row">  
        <input type="button" value="新增" class="btn btn-default" ng-click="firstCtrl.AddClick()" />  
        <input type="button" value="儲存" class="btn btn-default" ng-click="firstCtrl.SaveClick()" ng-disabled="!firstCtrl.SaveState" />  
    </div>  
    <br />  
    <div class="row">  
        <div ng-switch="firstCtrl.View">  
            <div ng-switch-when="add">  
                姓名:<input type="text" ng-model="firstCtrl.Add.Name" class="form-control" />  
                電話:<input type="text" ng-model="firstCtrl.Add.PhoneNumber" class="form-control" />  
                地址:<input type="text" ng-model="firstCtrl.Add.Address" class="form-control" />  
            </div>  
            <div ng-switch-default>  
                <table class="table">  
                    <tr>  
                        <th>姓名</th>  
                        <th>電話</th>  
                        <th>地址</th>  
                    </tr>  
                    <tr ng-repeat="item in firstCtrl.Student">  
                        <td>{{item.Name}}</td>  
                        <td>{{item.PhoneNumber}}</td>  
                        <td>{{item.Address}}</td>  
                    </tr>  
                </table>  
            </div>  
        </div>  
    </div>  
</div>  
@section scripts{   
<script src="~/App/Index.js"></script>  
}  
 

Index.js

angular.module('MyApp', [])   
    .controller('FirstCtrl', function ($http,$scope) {   
        var Url = 'http://localhost:65414/Api/'  
        var errorMessage = '發生錯誤';   
        var vm = this;   
           
        $http.get(Url + 'Values').success(function (data) {   
            vm.Student = data;   
        }).error(function () {   
            alert(errorMessage);   
        })   
  
        vm.AddClick = function () {   
            vm.View = 'add';   
            vm.SaveState = true;   
        } //改變狀態切換到add同時把儲存按鈕變成可以編輯   
  
        vm.SaveClick = function () {   
            $http.post(Url + 'Values',vm.Add).success(function (data) { //vm.Add是html的input值   
                vm.Student.push(data); //這一段我是直接從web api回傳單筆資料回來,然後直接對陣列新增,就沒在從資料庫把值取回來   
                vm.View = 'list';  //因為如果沒有相符就是default的狀態,所以我給list或null值都可以   
            }).error(function () {   
                alert(errorMessage);   
            })   
        }   
    });
 

因為程式碼有點多,所以我把說明直接寫在註解裡面,方便理解各行程式碼在做什麼事情

 

 

實做刪除和修改功能

 

這邊我在對原有的html和js加上刪修和修改功能,如下

Index.cshtml

<div class="row" ng-controller="FirstCtrl as firstCtrl">   
    <div class="row">   
        <input type="button" value="新增" class="btn btn-default" ng-click="firstCtrl.AddClick()" ng-hide="firstCtrl.AddHide" />   
        <input type="button" value="儲存" class="btn btn-default" ng-click="firstCtrl.SaveClick()" ng-disabled="!firstCtrl.SaveState" />   
    </div>   
    <br />   
    <div class="row">   
        <div ng-switch="firstCtrl.View">   
            <div ng-switch-when="add">   
                <h3>新增</h3>   
                姓名:<input type="text" ng-model="firstCtrl.Add.Name" class="form-control" />   
                電話:<input type="text" ng-model="firstCtrl.Add.PhoneNumber" class="form-control" />   
                地址:<input type="text" ng-model="firstCtrl.Add.Address" class="form-control" />   
            </div>   
            <div ng-switch-when="edit">   
                <h3>修改</h3>   
                <span ng-init="firstCtrl.Edit.ID"></span>   
                姓名:<input type="text" ng-model="firstCtrl.Edit.Name" class="form-control" />   
                電話:<input type="text" ng-model="firstCtrl.Edit.PhoneNumber" class="form-control" />   
                地址:<input type="text" ng-model="firstCtrl.Edit.Address" class="form-control" />   
            </div>   
            <div ng-switch-default>   
                <table class="table">   
                    <tr>   
                        <th></th>   
                        <th>姓名</th>   
                        <th>電話</th>   
                        <th>地址</th>   
                    </tr>   
                    <tr ng-repeat="item in firstCtrl.Student">   
                        <td>   
                            <input type="button" value="修改" class="btn btn-default" ng-click="firstCtrl.EditClick(item)" />   
                            <input type="button" value="刪除" class="btn btn-default" ng-click="firstCtrl.DeleteClick(item.ID,$index)" />   
                        </td>   
                        <td>{{item.Name}}</td>   
                        <td>{{item.PhoneNumber}}</td>   
                        <td>{{item.Address}}</td>   
                    </tr>   
                </table>   
            </div>   
        </div>   
    </div>   
</div>   
@section scripts{   
<script src="~/App/Index.js"></script>   
}  

 

Index.js

angular.module('MyApp', [])   
    .controller('FirstCtrl', function ($http,$scope) {   
        var Url = 'http://localhost:65414/Api/'  
        var errorMessage = '發生錯誤';   
        var vm = this;   
           
        $http.get(Url + 'Values').success(function (data) {   
            vm.Student = data;   
        }).error(function () {   
            alert(errorMessage);   
        })   
  
        vm.AddClick = function () {   
            vm.View = 'add';   
            vm.SaveState = true;   
        } //改變狀態切換到add同時把儲存按鈕變成可以編輯   
  
        vm.SaveClick = function () {   
            if (vm.View === 'add') { //判斷ng-switch狀態,因為我用同一個儲存按鈕同時做新增和修改動作   
                $http.post(Url + 'Values', vm.Add).success(function (data) { //vm.Add是html的input值   
                    vm.Student.push(data); //這一段我是直接從web api回傳單筆資料回來,然後直接對陣列新增,就沒在從資料庫把值取回來   
                    vm.View = 'list';  //因為如果沒有相符就是default的狀態,所以我給list或null值都可以   
                    vm.SaveState = false; //把儲存按鈕切換成不可編輯的狀態   
                }).error(function () {   
                    alert(errorMessage);   
                })   
            } else {   
                $http.put(Url + 'Values', vm.Edit).success(function () { //vm.Edit是html裡的input值   
                    vm.View = 'list';   
                    vm.SaveState = false;   
                }).error(function () {   
                    alert(errorMessage);   
                })   
            }   
        }   
  
        vm.EditClick = function (item) {   
            vm.View = 'edit';   
            vm.SaveState = true;   
            vm.Edit = item;   
        }   
  
        vm.DeleteClick = function (ID,Index) { //ID是從前端傳過來,為了丟到後端做刪除動作,Index則是我要直接刪除陣列,不在從後端傳來資料   
            $http.delete(Url + 'Values/'+ID).success(function () {   
                vm.Student.splice(Index);   
            }).error(function () {   
                alert(errorMessage);u   
            })   
        }   
    });  

 

整個操作的示意畫面大約如下

 

image53

 

image65

image62

image71

image74

 

總結

 

以上最主要是示範$http的做法,不過實際上我們在做表單還需要考慮到前端驗證的部份,所以正規來說我們會使用ng-submit來實做,但如果要放在同一篇來解釋,文章會變得非常長,所以留著下一篇再解釋,這邊程式碼比較多,所以我會在底下放個github的原始碼,可下載原始碼回去查看,然後試著run看看,需注意一下,connection需要改成自己的連線,以上再請多多指教。

 

https://github.com/kinanson/angularjs-http-sample