翻譯:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 設計和開發站點 - 3


原文地址:http://ddmvc4.codeplex.com/

原文名稱:Design and Develop a website using ASP.NET MVC 4, EF, Knockoutjs and Bootstrap

Part 1: 創建 Web Application (Knockout.js, Asp.Net MVC and Bootstrap): 前端設計

在開始 UI 部分之前,我們先看一下在 ASP.NET MVC4 中使用 Knockoutjs 和 Bootstrap 有什么好處?


Why Knockoutjs: Knockout 使用 JavaScript ViewModel 實現了 MVVM 模式. 在 MVC 中還有一個很棒的因素是從 Javascript 模型序列化為 Json 和從 Json 反序列為模型都很簡單,在 MVC4 中已經包含了這個腳本庫, 這使得在我們開發復雜的 UI 的時候,不論怎樣修改,都只需要很少的編碼,馬上我們用它來實現頁面。

Why Bootstrap: Twitter 的 Bootstrap 是包括簡單並且靈活的 HTML, CSS, 以及廣受歡迎的 Javascript 用戶界面組件和交互。包括一組 CSS 樣式,組件和 JavaScript 插件。提供了跨平台的支持, 消除了不同平台的不一致問題。處理的非常好,良好的文檔和 Twitter Bootstrap's 站點本事就是現實中很棒的參考。最后,它節省了我大量的時間,只需要很少的測試,幾乎沒有瀏覽器的問題,節約了一半的開發時間,在我們的框架中其它優點還包括。

  • 12-列表個, 固定布局, 流式布局以及響應式布局.
  • 提供基本的 CSS, 包括:版式, code (使用  Google prettify 的語法高亮), 表格, 表單, 按鈕,以及 Glpyhicons 圖標 .
  • Web UI 組件,例如 按鈕, 導航菜單, 標簽, 縮略圖, 提示, 進度條和其他雜項.
  • Javascript 插件,包括模式對話框, 下拉列表, 滾動條, 窗格, 工具提示, 彈出窗口, 提示, 按鈕, 收縮, 轉輪和提示.

在下面的步驟中,我們將演練使用測試數據來創建布局,設計 UI ,完成上述的目標。Step 1:

創建空白的應用; 命名為 “Application”
14.png

Step 2:

在解決方案上右擊鼠標,添加一個新的 ASP.NET MVC4 項目,選擇 Internet Application 模版,使用 Razor 引擎。

15.png
16.png

完成第 2 步之后 - 項目的結構如下所示
17.png

Step 3:

在 MVC 項目上鼠標右擊,選擇管理 NuGet 包,在搜索框中輸入 Bootstrap ,找到后,點擊 Install 按鈕。

18.png

有的時候,我會聯不到 NuGet 網站,你可以直接到 BootStrap 網站下載文件,添加到項目中。

主要是使用了樣式文件 bootstrap.css ,下載后,保存到 Content 文件夾中。

Step 4:

 

將下面的兩行代碼添加到 App_Start 文件夾中德 BundleConfig.cs 文件中,為所有頁面使用 Knockoutjs 和 Bootstrap 提供支持。

bundles.Add(new ScriptBundle("~/bundles/knockout").Include(
                                    "~/Scripts/knockout-{version}.js"));
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/bootstrap.css"));


在 Views/Shared 文件夾中 _Layout.cshtml 文件中,添加下面的行,注冊使用 knockout。

Also in _Layout,cshtml file under Views/Shared folder add below line to register knockout files as :

@Scripts.Render("~/bundles/knockout")

Step 5:

在視圖文件夾 Views 中添加一個名為 Contack 的文件夾,在其中添加一個名為 Index.cshtml 的視圖文件 ( 這一步可以通過在控制器中的 Index 方法上點擊右鍵完成 )。然后添加一個名為 ContactController 的控制器,在 Scripts 文件夾中添加一個名為 Contact.js 的腳本文件,項目文件夾如下所示:

19.png

Step 6:

修改 Route.config 文件,將默認的路由設置到 Contact 控制器。

routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Contact", action = "Index", id = UrlParameter.Optional }
            );

修改 View/Shared 文件夾中的 _Layout.cshtml 文件,使用 BootStrap 語法,修改后的代碼如下所示。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title - Contact manager</title>
    <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
    <meta name="viewport" content="width=device-width" />
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/knockout")
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
    @RenderSection("scripts", required: false)
</head>
<body>

    <div class="container-narrow">
        <div class="masthead">
            <ul class="nav nav-pills pull-right">
                
            </ul>
            <h3 class="muted">Contact Manager</h3>
        </div>
        <div id="body" class="container">
            @RenderSection("featured", required: false)
            <section>
                @RenderBody()
            </section>
        </div>
        <hr />
        <div id="footer">
            <div class="container">
                <p class="muted credit">&copy; @DateTime.Now.Year - Design and devloped by <a href="http://www.anandpandey.com">Anand Pandey</a>.</p>
            </div>
        </div>
    </div>

</body>
</html>

 

Step 7:

現在可以運行程序,效果如下:
20.png

我們使用這個頁面顯示 Screen 1 ,顯示聯系人列表。

Step 8:

 首先,我們在 Contact.js 中創建一個模擬的聯系人數據數組,  (最后我們從數據庫中獲取), 隨后,我們使用這些數據填充表格。

var DummyProfile = [
    {
        "ProfileId": 1,
        "FirstName": "Anand",
        "LastName": "Pandey",
        "Email": "anand@anandpandey.com"
    },
    {
        "ProfileId": 2,
        "FirstName": "John",
        "LastName": "Cena",
        "Email": "john@cena.com"
    }
]

然后,我們創建 ProfilesViewModel, ViewModel 用來保存聯系人信息,數組用來保存聯系人信息的集合。注意這里使用 ko.observableArray,         相當於常規數組,是觀察者模式中的主題,這意味着它可以在其中的項目發生變化的時候,自動更新界面。

 最后,我們需要使用 ko.applyBindings() 來激活 knockout.

var ProfilesViewModel = function () {
    var self = this;
    var refresh = function () {
        self.Profiles(DummyProfile);
    };
 
    // Public data properties
    self.Profiles = ko.observableArray([]);
    refresh();
};
ko.applyBindings(new ProfilesViewModel());

Step 9:

下一步,我們需要在 Index.cshtml 頁面寫一些代碼。以顯示聯系人列表。我們在 tbody 元素上使用 foreach 綁定,使用 knockout 根據聯系人數組中的每一個數據生成對應的子元素,然后告訴 knockout 我們希望使用對每個數據生成 tr 來填充 tbody.

<table class="table table-striped table-bordered table-condensed">
    <tr> 
        <th>First Name</th>
        <th>Last Name</th>
        <th>Email</th>
    </tr>
    <tbody data-bind="foreach: Profiles">
        <tr>
            <td data-bind="text: FirstName"></td>
            <td data-bind="text: LastName"></td>
            <td data-bind="text: Email"></td>
        </tr>
    </tbody>
</table>
 
<script src="~/Scripts/Contact.js"></script>
 
        

如果現在運行程序,就會看到聯系人的簡單列表
21.png
不要忘了,我們使用 Bootstrap 的樣式類來應用到 table 上,在上邊的例子中,如下所示。

<table class="table table-striped table-bordered table-condensed">


Step 10:

現在,我們需要為每一行增加編輯和刪除功能,表格的上邊有一個創建新聯系人的按鈕,做以下工作:

  • 在模版中添加 th 和 td ,在腳本中綁定 removeProfile 函數處理按鈕的點擊事件處理
  • 修改名字單元格,增加編輯聯系人的鏈接,使用 editProfile 函數綁定點擊事件
  • 在表格的前面添加創建聯系人的按鈕,使用 createProfile 函數綁定到點擊事件處理

頁面內容如下所示 :

<input type="button"  class="btn btn-small btn-primary"  value="New Contact" data-bind="click:$root.createProfile" />
<hr />
<table class="table table-striped table-bordered table-condensed">
    <tr> 
        <th>First Name</th>
        <th>Last Name</th>
        <th>Email</th>
        <th></th>
    </tr>
    <tbody data-bind="foreach: Profiles">
        <tr>
            <td class="name"><a data-bind="text: FirstName, click: $parent.editProfile"></a></td>
            <td data-bind="text: LastName"></td>
            <td data-bind="text: Email"></td>
            <td><button class="btn btn-mini btn-danger" data-bind="click: $parent.removeProfile">remove</button></td>
        </tr>
    </tbody>
</table>
 
<script src="~/Scripts/Contact.js"></script>

執行的效果如下所示:
22.png
但是現在按鈕都不能工作,因為我們還沒有編寫響應的代碼,下一步我們來處理這個問題。

Step 11:

在 Contact.js 中,編寫  createProfile 函數, editProfile 函數,以及 removeProfile 函數。

self.createProfile = function () {
        alert("Create a new profile");
    };
 
    self.editProfile = function (profile) {
        alert("Edit tis profile with profile id as :" + profile.ProfileId);
    };
 
    self.removeProfile = function (profile) {
        if (confirm("Are you sure you want to delete this profile?")) {
            self.Profiles.remove(profile);
        }
    };
 
        

現在運行程序,點擊刪除聯系人按鈕,將會從數組中刪除當前的聯系人。由於我們定義了一個觀察者數組,所以,UI 界面會與數組保持同步。點擊刪除按鈕可以測試一下。編輯鏈接和創建聯系人鏈接只是簡單地彈出一個提示框,下一步我們實現它們。

Step 12:

下面我們會增加:

 

  • 在 ContactController.cs 類中增加一個 CreateEdit 的 Action 方法,並添加對應的視圖。
public ActionResult CreateEdit()
{
            return View();
 }

 

  • 在 Scripts 文件夾中增加一個名為 CreateEdit.js 的新腳本文件
  • 修改Contact.js 中的 createProfile 和 editProfile 方法, 以便指向 CreateEdit 頁面。

 

self.createProfile = function () {
        window.location.href = '/Contact/CreateEdit/0';
};
 
self.editProfile = function (profile) {
        window.location.href = '/Contact/CreateEdit/' + profile.ProfileId;
};
 
        

重新運行程序,所有的事件處理都可以工作了。創建和編輯聯系人會定有參數的重定向到 CreateEdit 頁面。

Step 13:

首先,我們從 CreateEdit 頁面的添加聯系人信息開始,我們需要如下的工作:

我們需要從 Url 中獲取聯系人的標識,下面的前兩行處理這個問題。

var url = window.location.pathname;
var profileId = url.substring(url.lastIndexOf('/') + 1);
var DummyProfile = [
    {
        "ProfileId": 1,
        "FirstName": "Anand",
        "LastName": "Pandey",
        "Email": "anand@anandpandey.com"
    },
    {
        "ProfileId": 2,
        "FirstName": "John",
        "LastName": "Cena",
        "Email": "john@cena.com"
    }
]

Profile 是一個簡單的 Javascript 類,用來存儲聯系人的姓名和電子郵件。

var Profile = function (profile) {
    var self = this;
 
    self.ProfileId = ko.observable(profile ? profile.ProfileId : 0);
    self.FirstName = ko.observable(profile ? profile.FirstName : '');
    self.LastName = ko.observable(profile ? profile.LastName : '');
    self.Email = ko.observable(profile ? profile.Email : '');
};

ProfileCollection,是一個 ViewModel 類,用來保存聯系人信息,處理 saveProfile 和 backToProfileList 事件。

var ProfileCollection = function () {
    var self = this;
 
    //if ProfileId is 0, It means Create new Profile
    if (profileId == 0) {
        self.profile = ko.observable(new Profile());
    }
    else {
        var currentProfile = $.grep(DummyProfile, function (e) { return e.ProfileId == profileId; });
        self.profile = ko.observable(new Profile(currentProfile[0]));
    }
 
    self.backToProfileList = function () { window.location.href = '/contact'; };
 
    self.saveProfile = function () {
        alert("Date to save is : " + JSON.stringify(ko.toJS(self.profile())));
    };
};

最后,使用 ko.applyBindings() 激活 Knockout.

ko.applyBindings(new ProfileCollection());


Step 14:

下一步,我們需要在 CreateEdit.cshtml 頁面寫代碼以支持顯示聯系人信息。我們需要使用 with 綁定聯系人數據,以便它生成特定聯系人的響應子元素,並賦予適當的值。代碼如下:

<table class="table">
        <tr>
            <th colspan="3">Profile Information</th>
        </tr>
        <tr></tr>
    <tbody data-bind='with: profile'>
        <tr>
            <td>
                <input class="input-large" data-bind='value: FirstName'  placeholder="First Name"/>
            </td>
            <td>
                <input class="input-large" data-bind='value: LastName' placeholder="Last Name"/>
            </td>
            <td>
                <input class="input-large" data-bind='value: Email' placeholder="Email" />
            </td>
        </tr>
    </tbody>
</table>
 
<button class="btn btn-small btn-success" data-bind='click: saveProfile'>Save Profile</button>
<input class="btn btn-small btn-primary" type="button" value="Back To Profile List" data-bind="click:$root.backToProfileList" />
 
<script src="~/Scripts/CreateEdit.js"></script>

當創建新聯系人的時候。

23.png

編輯現有的編號為 1 的聯系人的時候:
24.png

更新現有的數據,點擊保存的時候:
25.png

對於這個界面的每個需求,我們已經完成:

2.1 用戶可以編輯姓名,電子郵件地址。
2.6 點擊保存按鈕保存到數據庫,返回聯系人列表。
2.7 點擊返回,回到聯系人列表。

下面我們處理下面的兩個需求:
2.2 通過點擊添加按鈕,用戶可以為聯系人增加多個電話
2.3 用戶可以刪除電話

Step 15:

  為了達到 2.2 和 2.3 的需求,我們需要:
在 CreateEdit.js 中定義一個假的 PhoneType 和 PhoneDTO 數據數組。phoneTypeData 將用來綁定到下列列表.

var phoneTypeData = [
    {
        "PhoneTypeId": 1,
        "Name": "Work Phone"
    },
    {
        "PhoneTypeId": 2,
        "Name": "Personal Phone"
    }
];
 
var PhoneDTO = [
    {
        "PhoneId":1,
        "PhoneTypeId": 1,
        "ProfileId":1,
        "Number": "111-222-3333"
    },
    {
        "PhoneId": 2,
        "PhoneTypeId": 2,
        "ProfileId": 1,
        "Number": "444-555-6666"
    }
];

PhoneLine 是一個 JavaScript 類,用來保存一行電話信息,

var PhoneLine = function (phone) {
    var self = this;
    self.PhoneId = ko.observable(phone ? phone.PhoneId : 0);
    self.PhoneTypeId = ko.observable(phone ? phone.PhoneTypeId : 0);
    self.Number = ko.observable(phone ? phone.Number : '');
};

修改 ProfileCollection ViewModel 類,對於 addPhone 和 removePhone 事件保存電話號碼。

var ProfileCollection = function () {
    var self = this;
 
    //if ProfileId is 0, It means Create new Profile
    if (profileId == 0) {
        self.profile = ko.observable(new Profile());
        self.phoneNumbers = ko.observableArray([new PhoneLine()]);
    }
    else {
        var currentProfile = $.grep(DummyProfile, function (e) { return e.ProfileId == profileId; });
        self.profile = ko.observable(new Profile(currentProfile[0]));
        var currentProfilePhone = $.grep(PhoneDTO, function (e) { return e.ProfileId == profileId; });
        self.phoneNumbers = ko.observableArray(ko.utils.arrayMap(currentProfilePhone, function (phone) {
            return phone;
        }));
    }
 
    self.addPhone = function () {
        self.phoneNumbers.push(new PhoneLine())
    };
 
    self.removePhone = function (phone) { self.phoneNumbers.remove(phone) };
 
    self.backToProfileList = function () { window.location.href = '/contact'; };
 
    self.saveProfile = function () {
        alert("Date to save is : " + JSON.stringify(ko.toJS(self.profile())));
    };
};

 

 
        

Step 16:

下一步我們在 CreateEdit.cshtml 頁面中添加過個節來添加電話信息。一個聯系人可以擁有多個不同類型的電話,我們使用 foreach 綁定來處理電話數據,在 CreateEdit.cshtml 中添加下面的節,位置在聯系人信息之后,保存按鈕之前。

<table class="table">
        <tr>
            <th colspan="3">Phone Information</th>
        </tr>
        <tr></tr>
    <tbody data-bind='foreach: phoneNumbers'>
        <tr>
            <td>
                <select data-bind="options: phoneTypeData, value: PhoneTypeId, optionsValue: 'PhoneTypeId', optionsText: 'Name', optionsCaption: 'Select Phone Type...'"></select>
            </td>
            <td>
                <input class="input-large" data-bind='value: Number' placeholder="Number" />
            </td>
            <td>
                <a class="btn btn-small btn-danger" href='#' data-bind=' click: $parent.removePhone'>X</a>
            </td>
        </tr>
    </tbody>
</table>
<p>
<button class="btn btn-small btn-primary" data-bind='click: addPhone'>Add New Phone</button>
</p>

現在運行界面如下:


26.png

編輯現有聯系人的界面:
27.png

現在只剩下下面的兩個需求:

2.4 用戶可以添加多個地址
2.5 用戶可以刪除地址

Step 17:

需求的 2.4 和 2.5 類似電話處理, 下面是最終的代碼:

CreateEdit.js

var url = window.location.pathname;
var profileId = url.substring(url.lastIndexOf('/') + 1);
 
var DummyProfile = [
    {
        "ProfileId": 1,
        "FirstName": "Anand",
        "LastName": "Pandey",
        "Email": "anand@anandpandey.com"
    },
    {
        "ProfileId": 2,
        "FirstName": "John",
        "LastName": "Cena",
        "Email": "john@cena.com"
    }
];
 
var PhoneTypeData = [
    {
        "PhoneTypeId": 1,
        "Name": "Work Phone"
    },
    {
        "PhoneTypeId": 2,
        "Name": "Personal Phone"
    }
];
 
var PhoneDTO = [
    {
        "PhoneId":1,
        "PhoneTypeId": 1,
        "ProfileId":1,
        "Number": "111-222-3333"
    },
    {
        "PhoneId": 2,
        "PhoneTypeId": 2,
        "ProfileId": 1,
        "Number": "444-555-6666"
    }
];
 
var AddressTypeData = [
    {
        "AddressTypeId": 1,
        "Name": "Shipping Address"
    },
    {
        "AddressTypeId": 2,
        "Name": "Billing Address"
    }
];
 
var AddressDTO = [
    {
        "AddressId": 1,
        "AddressTypeId": 1,
        "ProfileId": 1,
        "AddressLine1": "10000 Richmond Avenue",
        "AddressLine2": "Apt # 1000",
        "Country": "USA",
        "State": "Texas",
        "City": "Houston",
        "ZipCode": "70000"
    },
    {
        "AddressId": 2,
        "AddressTypeId": 2,
        "ProfileId": 1,
        "AddressLine1": "20000 Highway 6",
        "AddressLine2": "Suite # 2000",
        "Country": "USA",
        "State": "Texas",
        "City": "Houston",
        "ZipCode": "80000"
    }
];
 
 
var Profile = function (profile) {
    var self = this;
 
    self.ProfileId = ko.observable(profile ? profile.ProfileId : 0);
    self.FirstName = ko.observable(profile ? profile.FirstName : '');
    self.LastName = ko.observable(profile ? profile.LastName : '');
    self.Email = ko.observable(profile ? profile.Email : '');
    self.PhoneDTO = ko.observableArray(profile ? profile.PhoneDTO : []);
    self.AddressDTO = ko.observableArray(profile ? profile.AddressDTO : []);
};
 
var PhoneLine = function (phone) {
    var self = this;
    self.PhoneId = ko.observable(phone ? phone.PhoneId : 0);
    self.PhoneTypeId = ko.observable(phone ? phone.PhoneTypeId : 0);
    self.Number = ko.observable(phone ? phone.Number : '');
};
 
var AddressLine = function (address) {
    var self = this;
    self.AddressId = ko.observable(address ? address.AddressId : 0);
    self.AddressTypeId = ko.observable(address ? address.AddressTypeId : 0);
    self.AddressLine1 = ko.observable(address ? address.AddressLine1 : '');
    self.AddressLine2 = ko.observable(address ? address.AddressLine2 : '');
    self.Country = ko.observable(address ? address.Country : '');
    self.State = ko.observable(address ? address.State : '');
    self.City = ko.observable(address ? address.City : '');
    self.ZipCode = ko.observable(address ? address.ZipCode : '');
};
 
 
var ProfileCollection = function () {
    var self = this;
 
    //if ProfileId is 0, It means Create new Profile
    if (profileId == 0) {
        self.profile = ko.observable(new Profile());
        self.phoneNumbers = ko.observableArray([new PhoneLine()]);
        self.addresses = ko.observableArray([new AddressLine()]);
    }
    else {
        //For Profile information
        var currentProfile = $.grep(DummyProfile, function (e) { return e.ProfileId == profileId; });
        self.profile = ko.observable(new Profile(currentProfile[0]));
        //For Phone number
        var currentProfilePhone = $.grep(PhoneDTO, function (e) { return e.ProfileId == profileId; });
        self.phoneNumbers = ko.observableArray(ko.utils.arrayMap(currentProfilePhone, function (phone) {
            return phone;
        }));
        //For Address
        var currentProfileAddress = $.grep(AddressDTO, function (e) { return e.ProfileId == profileId; });
        self.addresses = ko.observableArray(ko.utils.arrayMap(currentProfileAddress, function (address) {
            return address;
        }));
    }
 
    self.addPhone = function () { self.phoneNumbers.push(new PhoneLine()) };
 
    self.removePhone = function (phone) { self.phoneNumbers.remove(phone) };
 
    self.addAddress = function () { self.addresses.push(new AddressLine()) };
 
    self.removeAddress = function (address) { self.addresses.remove(address) };
 
    self.backToProfileList = function () { window.location.href = '/contact'; };
 
    self.saveProfile = function () {
        self.profile().AddressDTO = self.addresses;
        self.profile().PhoneDTO = self.phoneNumbers;
        alert("Date to save is : " + JSON.stringify(ko.toJS(self.profile())));
    };
};
 
ko.applyBindings(new ProfileCollection());


 CreateEdit.cshtml

<table class="table">
        <tr>
            <th colspan="3">Profile Information</th>
        </tr>
        <tr></tr>
    <tbody data-bind='with: profile'>
        <tr>
            <td>
                <input class="input-large" data-bind='value: FirstName'  placeholder="First Name"/>
            </td>
            <td>
                <input class="input-large" data-bind='value: LastName' placeholder="Last Name"/>
            </td>
            <td>
                <input class="input-large" data-bind='value: Email' placeholder="Email" />
            </td>
        </tr>
    </tbody>
</table>
 
<table class="table">
        <tr>
            <th colspan="3">Phone Information</th>
        </tr>
        <tr></tr>
    <tbody data-bind='foreach: phoneNumbers'>
        <tr>
            <td>
                <select data-bind="options: PhoneTypeData, value: PhoneTypeId, optionsValue: 'PhoneTypeId', optionsText: 'Name', optionsCaption: 'Select Phone Type...'"></select>
            </td>
            <td>
                <input class="input-large" data-bind='value: Number' placeholder="Number" />
            </td>
            <td>
                <a class="btn btn-small btn-danger" href='#' data-bind=' click: $parent.removePhone'>X</a>
            </td>
        </tr>
    </tbody>
</table>
<p>
<button class="btn btn-small btn-primary" data-bind='click: addPhone'>Add New Phone</button>
</p>
<hr />
<table class="table">
    <tr><th colspan="5">Address Information</th></tr>
    <tbody data-bind="foreach: addresses">
        <tr>
            <td colspan="5">
                <select data-bind="options: AddressTypeData, value: AddressTypeId, optionsValue: 'AddressTypeId', optionsText: 'Name', optionsCaption: 'Select Address Type...'"></select>
            </td>
        </tr>
        <tr>
            <td>
                <input class="input-large" data-bind='value: AddressLine1' placeholder="Address Line1" />
                <p style="padding-top: 5px;"><input class="input-large" data-bind='value: State' placeholder="State" /></p>
            </td>
            <td>
                <input class="input-large" data-bind=' value: AddressLine2' placeholder="Address Line2" />
                <p style="padding-top: 5px;"><input class="input-large" data-bind='value: Country' placeholder="Country" /></p>
            </td>
            <td>
                <input class="input-large" data-bind='value: City' placeholder="City" />
                <p style="padding-top: 5px;"><input class="input-large" data-bind='value: ZipCode' placeholder="Zip Code" />
                <a class="btn btn-small btn-danger" href='#' data-bind='click: $root.removeAddress'>X</a></p>
            </td>
        </tr>
    </tbody>
</table>
<p>
<button class="btn btn-small btn-primary" data-bind='click: addAddress'>Add New Address</button>
</p>
<hr />
<button class="btn btn-small btn-success" data-bind='click: saveProfile'>Save Profile</button>
<input class="btn btn-small btn-primary" type="button" value="Back To Profile List" data-bind="click:$root.backToProfileList" />
 
<script src="~/Scripts/CreateEdit.js"></script>
 
        

最后,我們完成了每一個需求。

Screen 1: Contact List -顯示所有聯系人
28.png

Screen 2: 創建聯系人
29.png

Screen 3: 更新聯系人
30.png

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM