目前剛好配合公司的需求,開發簡易的平台簡化繁雜的作業流程,正好練練我的MVC和Angular 的分頁效果,當然還是有遇到不少困難啦~ 可以當作借鏡也給各位參考啦!
一、分頁的頁數
本案例用到async Task<T>的宣告型別,能非同步的傳輸模式,可以加快瀏覽的速度,不過注意的是宣告async Task,呼叫方式要用await
Model層: entityTestData.cs
public class entityTestData
{
double paging = 5; //設定分頁=5
public async Task<int> totalCount()
{
return i_cpNewDb.test_notice.Count();
//作者省略try{}catch{} 比較方便看code,各位還是要加上
}
public async Task<int> pageCount(int totalCount)
{
double pageCount = Math.Ceiling(totalCount / paging);
return Convert.ToInt32(pageCount);
}
//列表
public IEnumerable<viewAnnounce> search(int currentPage, string productType, string fileName, string fileVersion)
{
int intPagging = 0;
intPagging = Convert.ToInt32(paging);
var query = from q in
i_cpNewDb.test_notice
orderby q.ikey descending
select new viewAnnounce()
{
ikey = q.ikey,
productType = q.產品類別,
fileName = q.檔案名稱,
fileVersion = q.版本,
context = q.主旨,
updateTime = q.修改日期,
testFilePath = q.測試檔案路徑,
downloadFile = q.測試文件路徑,
isRelease = q.釋出正式版
};
if (!string.IsNullOrEmpty(productType))
{
query =
query.Where(q => q.productType.Contains(productType.Trim()));
}
if (!string.IsNullOrEmpty(fileName))
{
query =
query.Where(q => q.fileName.Contains(fileName.Trim()));
}
if (!string.IsNullOrEmpty(fileVersion))
{
query =
query.Where(q => q.fileVersion.Contains(fileVersion.Trim()));
}
//分頁時需要注意第 ? 筆開始取 n 筆,本案例設為分頁5筆
IEnumerable<viewAnnounce> liResult =
query.AsEnumerable<viewAnnounce>().Skip((currentPage - 1) *
intPagging).Take(intPagging).AsQueryable();
return liResult;
}
//因為有用到跨資料庫的案例,供給大家參考範例,和分頁的本身無相關喔!
public IEnumerable<viewBug> listBugs(int announceIkey)
{
string eSQL = @"select
a.ikey as ikey, a.announcement_ikey as announcementIkey,a.uid as uid,b.產品類別 as productType, a.測試檔案 as bugDocumentFile , a.回報結果 as bugContext,b.檔案名稱 as fileName,b.版本 as fileVersion,c.name as userName from bug_notice a
left join test_notice b on
a.announcement_ikey = b.ikey
left join TCS.dbo.alluser c on (a.uid = c.uid) where
a.announcement_ikey=@Announcement";
SqlParameter sp = new SqlParameter("Announcement", announceIkey);
sp.SqlDbType =
System.Data.SqlDbType.Int;
var results = i_cpNewDb.Database.SqlQuery<viewBug>(eSQL, sp ).AsEnumerable();
IList<viewBug> liBugs = new List<viewBug>();
foreach (var data in results)
{
liBugs.Add(data);
}
return liBugs.AsEnumerable<viewBug>();
}
}
|
Controller:
public class TestController : Controller
{
//將總頁數傳回頁面
public async Task<ActionResult> Announce()
{
int totalCount = await entityTestObj.totalCount();
ViewBag.totalCount = await entityTestObj.pageCount(totalCount);
return View(ViewBag);
}
[HttpPost]
public ActionResult SearchAnnounce(int currentPage, string searchProductType, string searchFileName, string searchFileVersion)
{
var result = entityTestObj.search(currentPage,
searchProductType, searchFileName, searchFileVersion);
return Json(result); //以json格式傳送資料給angularjs時,接收參數有datetime格式,需另外處理喔~
}
}
|
API Controller
在函式上方加上 [HttpGet] 和 [Route("api/…/}")]
就可以用GET協定分別呼叫URL,舉例 $
http.Get('../api/ApiTest/listBugNote/' +$scope.hiddenAnnounceIkey)
。
public class ApiTestController : ApiController
{
entityTestData entityTestObj = new entityTestData(); //呼叫實體層
public IEnumerable<viewAnnounce> Get()
{
return entityTestObj.listNewNotice();
}
[HttpGet]
[Route("api/ApiTest/readTestNote/{announceIkey}")]
public viewAnnounce Get(int announceIkey)
{
return entityTestObj.read(ikey);
}
[HttpGet]
[Route("api/ApiTest/listBugNote/{announceIkey}")]
public IEnumerable<viewBug> listBugNote(int announceIkey)
{
return entityTestObj.listBugs(announceIkey);
}
}
|
View:
如果Form表單中含有傳送檔案時,請記得在FORM的屬性加上enctype="multipart/form-data",你的檔案才能送到後端。
<form ng-controller="announceController" enctype="multipart/form-data">
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table style="border:0px;border-spacing: 10px;">
<tr>
<td style="padding: 6px;"><p data-placement="top"><button class="btn
btn-primary btn-xs" data-title="search" data-toggle="modal" data-target="#search"><span class="glyphicon
glyphicon-search"></span></button></p></td>
</tr>
</table>
<table id="mytable" class="table table-bordred table-striped">
<thead>
<th>編號</th>
<th>類別</th>
<th>名稱</th>
<th>版本</th>
<th>更新日期</th>
<th>主旨</th>
<th>文件檔案</th>
<th>測試檔案路徑</th>
<th>釋出</th>
<th>Line</th>
</thead>
<tbody>
<tr ng-repeat="testData in testNodes">
<td>{{testData.ikey}}</td>
<td>{{testData.productType}}</td>
<td>{{testData.fileName}}</td>
<td>{{testData.fileVersion}}</td>
<td>
//在JSON格式的傳回值中,如果有DATETIME,需要用Angular的filter特別處理字串
{{testData.updateTime | mydate | date:"yyyy/MM/dd ' ' h:mma"}}
</td>
<td>{{testData.context | limitTo: 15}} {{testData.context.length < 15 ? '' : '...'}}</td>
<td><a href="~/documentFile/{{testData.downloadFile}}">{{testData.downloadFile}}</a></td>
<td>{{testData.testFilePath}}</td>
<td>{{testData.isRelease}}</td>
<td>
<a href="#" ng-click="line(testData.fileName,
testData.fileVersion)"><img src="~/Images/linebutton_20x20_en.png" width="20" height="20" /></a>
</td>
</tr>
</tbody>
</table>
<ul class="pagination pull-right">
<li><a href="#" ng-click="prePage(currentPage)"><span class="glyphicon glyphicon-chevron-left"></span></a></li>
<li ng-repeat="page in pages" ng-click="setPage(page)" ng-class="{'active': page == currentPage}"><a href="#">{{page}}</a></li>
<li><a href="#" ng-click="nextPage(currentPage)"><span class="glyphicon glyphicon-chevron-right"></span></a></li>
</ul>
</div>
</div>
</div>
</div>
//查詢畫面
<div class="modal fade" id="search" tabindex="-1" role="dialog" aria-labelledby="search" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" id="closeAddForm" class="close" data-dismiss="modal" aria-hidden="true"><span class="glyphicon
glyphicon-remove" aria-hidden="true"></span></button>
<h4 class="modal-title custom_align" id="Heading">查詢</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label>類別</label>
<select class="form-control" ng-model="searchProductType"
ng-options="productType.key for productType in productsClassification
">
<option value=""></option>
</select>
</div>
<div class="form-group">
<label>檔名</label>
<input ng-model="searchFileName" class="form-control " type="text" placeholder="請輸入檔名">
</div>
<div class="form-group">
<label>版本</label>
<input ng-model="searchFileVersion" class="form-control " type="text" placeholder="1.0.0.0">
</div>
</div>
<div class="modal-footer ">
<button type="button" class="btn btn-warning btn-lg" ng-click="searchSubmit()" style="width: 100%;"><span class="glyphicon
glyphicon-ok-sign"></span>查詢</button>
</div>
</div>
</div>
</div>
</form>
|
Mydate : json的時間格式傳回值會變成DATE("數字"),所以要取字串第六碼以後的值,再將其轉換成數字型態,才能透過Angular的內建filter格式直接轉換日期
app.filter("mydate", function() {
return function (x) {
return new Date(parseInt(x.substr(6)));
};
});
|
pageFactory:用來處理畫面上的上一頁、下一頁、點選的頁面的頁數
app.factory('pageFactory', function ($http ) {
var totalCount = @ViewBag.totalCount; //Asp.net MVC參數可以直接在angular中使用
var currentPage =1;
return{
getData:function (url) {
return $http.get(url).then(function(res){
return res.data;
});
},
postData:function(url, formData)
{
return($http.post(url,formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).then(function (res) {
return res.data;
}));
},
pageList:function(){
var arrayPage=[];
for(var i=1;i<=totalCount;i++){
arrayPage.push(i);
}
return arrayPage;
},
nextPage:function(thispage)
{
currentPage= thispage+1;
if(currentPage > totalCount)
{
currentPage=totalCount;
}
return currentPage;
},
prePage:function (thispage)
{
currentPage= thispage-1;
if(currentPage <= 0)
{
currentPage=1;
}
return currentPage;
},
setPage:function (thispage) {
currentPage =
thispage;
return currentPage;
},
nowPage:function(){
return currentPage;
}
}
});
|
announceController
分頁中如果有查詢功能,就要把值submit送出查詢,再把取回的資料設給列表的$scope變數,所以使用angular的post協定送出查詢的結果
var app = angular.module("servFileModel", []);
app.controller("announceController", function ($scope, $http, pageFactory,$q) {
$scope.currentPage
=pageFactory.nowPage();
$scope.pages=pageFactory.pageList(); //取得所有分頁陣列
//預設第一頁,將查詢的參數值往後端送
var tempObj = null;
var defaultFormData = new FormData();
defaultFormData.append("currentPage", 1);
defaultFormData.append("searchProductType", "");
defaultFormData.append("searchFileName", "");
defaultFormData.append("searchFileVersion", "");
var promise =
pageFactory.postData('../Test/SearchAnnounce',defaultFormData).then(function(response) {
$scope.testNodes=response;
});
$scope.nextPage = function (currentPage) {
$scope.currentPage =
pageFactory.nextPage(currentPage);
var nextFormData = new FormData();
nextFormData.append("currentPage",
$scope.currentPage);
nextFormData.append("searchProductType",
($scope.searchProductType==undefined) ? "" : $scope.searchProductType.key);
nextFormData.append("searchFileName", ($scope.searchFileName==undefined)?
"" : $scope.searchFileName);
nextFormData.append("searchFileVersion",
($scope.searchFileVersion==undefined)? "" : $scope.searchFileVersion);
var promise =
pageFactory.postData('../Test/SearchAnnounce',nextFormData).then(function(response) {
$scope.testNodes=response;
});
}
$scope.prePage=function (currentPage) {
$scope.currentPage =
pageFactory.prePage(currentPage);
var preFormData = new FormData();
preFormData.append("currentPage",
$scope.currentPage);
preFormData.append("searchProductType",
($scope.searchProductType==undefined) ? "" : $scope.searchProductType.key);
preFormData.append("searchFileName",
($scope.searchFileName==undefined)? "" : $scope.searchFileName);
preFormData.append("searchFileVersion",
($scope.searchFileVersion==undefined)? "" : $scope.searchFileVersion);
var promise =
pageFactory.postData('../Test/SearchAnnounce',preFormData).then(function(response) {
$scope.testNodes=response;
});
}
$scope.setPage=function (currentPage) {
$scope.currentPage = pageFactory.setPage(currentPage);
var setCurrentFormData = new FormData();
setCurrentFormData.append("currentPage", $scope.currentPage);
setCurrentFormData.append("searchProductType", ($scope.searchProductType==undefined) ? "" : $scope.searchProductType.key);
setCurrentFormData.append("searchFileName", ($scope.searchFileName==undefined)? "" : $scope.searchFileName);
setCurrentFormData.append("searchFileVersion", ($scope.searchFileVersion==undefined)? "" : $scope.searchFileVersion);
var promise = pageFactory.postData('../Test/SearchAnnounce',setCurrentFormData).then(function(response) {
$scope.testNodes=response;
});
}
$scope.productsClassification=[
{"key": "COOPER"},{"key":"i_cpnews"},{"key":"健康檢查"},{"key":"簡訊"},{"key":"沖帳"},{"key":"口檢"},{"key":"病歷簽章"},{"key":"病歷抽審"},{"key":"巡迴醫療"},{"key":"其他"},];
$scope.searchSubmit=function () {
$('#search').modal('hide');
var reflashFormData = new FormData();
reflashFormData.append("currentPage", $scope.currentPage);
reflashFormData.append("searchProductType", ($scope.searchProductType==undefined) ? "" : $scope.searchProductType.key);
reflashFormData.append("searchFileName", ($scope.searchFileName==undefined)? "" : $scope.searchFileName);
reflashFormData.append("searchFileVersion", ($scope.searchFileVersion==undefined)? "" : $scope.searchFileVersion);
var promise =
pageFactory.postData('../Test/SearchAnnounce',reflashFormData).then(function(response) {
$scope.testNodes=response;
});
}
$scope.line=function (fileName,fileVersion) {
// line 的分享,目前只支援到行動APP,所以電腦版的LINE 目前並不支援
var lineURL = "line://msg/text/檔名:"+fileName.trim()+" 版本:"+fileVersion.trim()+" 目前已釋出測試版";
window.open(lineURL);
}
$("[data-toggle=tooltip]").tooltip();
});
|
成果展示:
以上是作者開發MVC和Angular的經驗談,感謝各位有耐心的讀完這篇文章,希望這篇文章對大家有幫助。
沒有留言:
張貼留言