確定在 chrome 110% 的時候若是放在 modal 中會遇到此問題
設定寬度為一個數值可以解決(設定100%無效)
javascript
====
$scope.getTableHeight = function () {
return {
height: $(window).height() - $('#divdetail').offset().top - (($(window).height() - $('#divdetail').closest('.modal-content').height()) / 2) - 20,
width: $('#divdetail').closest('td').width(),
}
};
html
====
<div id="divdetail" ag-grid="gridOptions" class="ag-green" style="margin-top:5px;" ng-style="getTableHeight()"></div>
2016年12月22日 星期四
2016年11月21日 星期一
filter by function 帶入自訂參數
javascript
====
$scope.filterFoods = function (detail) {
return function (food ) {
html
====
ng-options="food.value as food.text for food in foods | filter:filterFoods(detail)"
====
$scope.filterFoods = function (detail) {
return function (food ) {
html
====
ng-options="food.value as food.text for food in foods | filter:filterFoods(detail)"
2016年10月9日 星期日
使用 ag-grid headerCellRenderer 加入 select 或 input 時避免觸發排序
.directive("stoppropagation", function () {
return {
link: function (scope, element, attrs, ngModel) {
element.on('click', function (event) {
event.stopPropagation();
});
}
}
})
return {
link: function (scope, element, attrs, ngModel) {
element.on('click', function (event) {
event.stopPropagation();
});
}
}
})
2016年10月8日 星期六
使用 ag-grid cellrenderer 實作 CRUD 輸入文字時避免方向鍵造成焦點跑掉且自動將焦點停在input
在 input 中加入directive,select 也適用
.directive("stoppropagation", function () {
return {
link: function (scope, element, attrs, ngModel) {
element.on('keydown', function (event) {
var key = event.which || event.keyCode;
if (key >= 37 || key <= 40 || key==9) {
event.stopPropagation();
}
});
}
}
})
cellrenderer 中加入
params.eGridCell.addEventListener('focus', function (event) { event.srcElement.firstChild.focus(); event.srcElement.firstChild.select(); });
PS. 若為文字方塊再加入 event.srcElement.firstChild.select(); 以便自動全選
.directive("stoppropagation", function () {
return {
link: function (scope, element, attrs, ngModel) {
element.on('keydown', function (event) {
var key = event.which || event.keyCode;
if (key >= 37 || key <= 40 || key==9) {
event.stopPropagation();
}
});
}
}
})
cellrenderer 中加入
params.eGridCell.addEventListener('focus', function (event) { event.srcElement.firstChild.focus(); event.srcElement.firstChild.select(); });
PS. 若為文字方塊再加入 event.srcElement.firstChild.select(); 以便自動全選
2016年10月4日 星期二
使用頁籤效果切換顯示資料
<uib-tabset active="activeTab" > <uib-tab index="0" heading="繳款明細"> <div id="div繳款明細" ng-style="getTableHeightTab('div繳款明細')" ag-grid="gridOptionsPay" class="ag-green"></div> </uib-tab> <uib-tab index="1" heading="憑證明細"> <div id="div憑證明細" ng-style="getTableHeightTab('div憑證明細')" ag-grid="gridOptionsInvoice" class="ag-green"></div> </uib-tab> </uib-tabset>
透過css 調整底色方式
.nav-tabs > li.active > a, .nav-tabs > li.active > a:focus, .nav-tabs > li.active > a:hover {
background-color: aqua;
}
※$scope.activeTab=目前顯示tab 的index
※$scope.activeTab=目前顯示tab 的index
2016年8月24日 星期三
客製化 ng-options
改用 ng-repeat
例如依據顯示文字設定class
<style>
option[data-text*="未完成"] {
color: red;
}
</style>
<select ng-model="countrySelected">
<option ng-repeat="country in countries" value="{{country.CountryCode}}"
data-text="{{country.CurrencyName}}">{{country.CurrencyName}}</option>
</select>
例如依據顯示文字設定class
<style>
option[data-text*="未完成"] {
color: red;
}
</style>
<select ng-model="countrySelected">
<option ng-repeat="country in countries" value="{{country.CountryCode}}"
data-text="{{country.CurrencyName}}">{{country.CurrencyName}}</option>
</select>
2016年8月23日 星期二
使用 bootstrap toggle 搭配 ng-model
javascript
====
.directive("togglebox", function () {
return {
scope: {
element.on('change', function() {
var checked = element.prop('checked');
scope.$apply(function () {
}
}
})
html
====
<input togglebox="switch" type="checkbox" checked data-toggle="toggle" data-on="全部" data-off="營收" data-onstyle="success" data-offstyle="info">
bootstrap toggle
====
.directive("togglebox", function () {
return {
scope: {
togglebox: "=" // 設定 屬性值 綁定 ng-model
},
link: function (scope, element,ngModel) {element.on('change', function() {
var checked = element.prop('checked');
scope.$apply(function () {
scope.togglebox = checked; // 對應 $scope.switch
});
}); }
}
})
html
====
<input togglebox="switch" type="checkbox" checked data-toggle="toggle" data-on="全部" data-off="營收" data-onstyle="success" data-offstyle="info">
css (指定寬度,文字置中)
====
.toggle.btn {
width:80px !important;
min-height:28px;
}
.toggle-off.btn, .toggle-on.btn{
padding-left: 5px; padding-right: 5px;
}
bootstrap toggle
2016年7月12日 星期二
於 javascript 中產生檔案並下載 from table
<a href="#" id="link" download="@(ViewBag.Title).csv" style="display:block" class="btn btn-default" ng-click="download()">下載</a>
$scope.download = function () {
var str = "\uFEFF" + $('#table1').table2CSV({
delivery: 'value'
});
var dataUri = 'data:text/csv;charset=utf-8,' + encodeURIComponent(str);
document.getElementById('link').href = dataUri;
};
jQuery.fn.table2CSV = function (options) {
var options = jQuery.extend({
separator: ',',
header: [],
delivery: 'popup' // popup, value
},
options);
var csvData = [];
var headerArr = [];
var el = this;
//header
var numCols = options.header.length;
var tmpRow = []; // construct header avalible array
if (numCols > 0) {
for (var i = 0; i < numCols; i++) {
tmpRow[tmpRow.length] = formatData(options.header[i]);
}
} else {
$(el).find('thead').filter(':visible').find('th').each(function () {
if ($(this).css('display') != 'none') tmpRow[tmpRow.length] = formatData($(this).html());
});
}
row2CSV(tmpRow);
// actual data
$(el).find('tr').each(function () {
var tmpRow = [];
$(this).filter(':visible').find('td').each(function () {
if ($(this).css('display') != 'none') tmpRow[tmpRow.length] = formatData($(this).html());
});
row2CSV(tmpRow);
});
if (options.delivery == 'popup') {
var mydata = csvData.join('\n');
return popup(mydata);
} else {
var mydata = csvData.join('\n');
return mydata;
}
function row2CSV(tmpRow) {
var tmp = tmpRow.join('') // to remove any blank rows
// alert(tmp);
if (tmpRow.length > 0 && tmp != '') {
var mystr = tmpRow.join(options.separator);
csvData[csvData.length] = mystr;
}
}
function formatData(input) {
// replace " with 「
var regexp = new RegExp(/["]/g);
var output = input.replace(regexp, "「");
//HTML
var regexp = new RegExp(/\<[^\<]+\>/g);
var output = output.replace(regexp, "");
if (output == "") return '';
return '"' + output + '"';
}
function popup(data) {
var generator = window.open('', 'csv', 'height=400,width=600');
generator.document.write('<html><head><title>CSV</title>');
generator.document.write('</head><body >');
generator.document.write('<textArea cols=70 rows=15 wrap="off" >');
generator.document.write(data); generator.document.write('</textArea>');
generator.document.write('</body></html>');
generator.document.close();
return true;
}
};
$scope.download = function () {
var str = "\uFEFF" + $('#table1').table2CSV({
delivery: 'value'
});
var dataUri = 'data:text/csv;charset=utf-8,' + encodeURIComponent(str);
document.getElementById('link').href = dataUri;
};
jQuery.fn.table2CSV = function (options) {
var options = jQuery.extend({
separator: ',',
header: [],
delivery: 'popup' // popup, value
},
options);
var csvData = [];
var headerArr = [];
var el = this;
//header
var numCols = options.header.length;
var tmpRow = []; // construct header avalible array
if (numCols > 0) {
for (var i = 0; i < numCols; i++) {
tmpRow[tmpRow.length] = formatData(options.header[i]);
}
} else {
$(el).find('thead').filter(':visible').find('th').each(function () {
if ($(this).css('display') != 'none') tmpRow[tmpRow.length] = formatData($(this).html());
});
}
row2CSV(tmpRow);
// actual data
$(el).find('tr').each(function () {
var tmpRow = [];
$(this).filter(':visible').find('td').each(function () {
if ($(this).css('display') != 'none') tmpRow[tmpRow.length] = formatData($(this).html());
});
row2CSV(tmpRow);
});
if (options.delivery == 'popup') {
var mydata = csvData.join('\n');
return popup(mydata);
} else {
var mydata = csvData.join('\n');
return mydata;
}
function row2CSV(tmpRow) {
var tmp = tmpRow.join('') // to remove any blank rows
// alert(tmp);
if (tmpRow.length > 0 && tmp != '') {
var mystr = tmpRow.join(options.separator);
csvData[csvData.length] = mystr;
}
}
function formatData(input) {
// replace " with 「
var regexp = new RegExp(/["]/g);
var output = input.replace(regexp, "「");
//HTML
var regexp = new RegExp(/\<[^\<]+\>/g);
var output = output.replace(regexp, "");
if (output == "") return '';
return '"' + output + '"';
}
function popup(data) {
var generator = window.open('', 'csv', 'height=400,width=600');
generator.document.write('<html><head><title>CSV</title>');
generator.document.write('</head><body >');
generator.document.write('<textArea cols=70 rows=15 wrap="off" >');
generator.document.write(data); generator.document.write('</textArea>');
generator.document.write('</body></html>');
generator.document.close();
return true;
}
};
2016年7月7日 星期四
2016年7月1日 星期五
於 javascript 中產生檔案並下載 from json object
var str = "\uFEFF"+JSON2CSV(jsonobj);
var dataUri = 'data:text/csv;charset=utf-8,' + encodeURIComponent(str);
var link = document.getElementById('link').href = dataUri;
<a href="#" id="link" download="download.csv">下載</a>
function JSON2CSV(objArray) {
var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
var str = '';
var line = '';
//if ($("#labels").is(':checked')) {
var head = array[0];
if ($("#quote").is(':checked')) {
for (var index in array[0]) {
var value = index + "";
line += '"' + value.replace(/"/g, '""') + '",';
}
} else {
for (var index in array[0]) {
line += index + ',';
}
}
line = line.slice(0, -1);
str += line + '\r\n';
//}
for (var i = 0; i < array.length; i++) {
var line = '';
if ($("#quote").is(':checked')) {
for (var index in array[i]) {
var value = array[i][index] + "";
line += '"' + value.replace(/"/g, '""') + '",';
}
} else {
for (var index in array[i]) {
if (typeof array[i][index] == 'object' && array[i][index] != null) {
line += "\"";
for (var j = 0; j < array[i][index].length; j++) line += array[i][index][j] + '\n';
line += "\",";
}
else line += array[i][index] + ',';
}
}
line = line.slice(0, -1);
str += line + '\r\n';
}
return str;
}
動態產生HTML 元件達到下載效果
function downloadURI(uri, name) {
var link = document.createElement("a");
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
var dataUri = 'data:text/csv;charset=utf-8,' + encodeURIComponent(str);
var link = document.getElementById('link').href = dataUri;
<a href="#" id="link" download="download.csv">下載</a>
function JSON2CSV(objArray) {
var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
var str = '';
var line = '';
//if ($("#labels").is(':checked')) {
var head = array[0];
if ($("#quote").is(':checked')) {
for (var index in array[0]) {
var value = index + "";
line += '"' + value.replace(/"/g, '""') + '",';
}
} else {
for (var index in array[0]) {
line += index + ',';
}
}
line = line.slice(0, -1);
str += line + '\r\n';
//}
for (var i = 0; i < array.length; i++) {
var line = '';
if ($("#quote").is(':checked')) {
for (var index in array[i]) {
var value = array[i][index] + "";
line += '"' + value.replace(/"/g, '""') + '",';
}
} else {
for (var index in array[i]) {
if (typeof array[i][index] == 'object' && array[i][index] != null) {
line += "\"";
for (var j = 0; j < array[i][index].length; j++) line += array[i][index][j] + '\n';
line += "\",";
}
else line += array[i][index] + ',';
}
}
line = line.slice(0, -1);
str += line + '\r\n';
}
return str;
}
動態產生HTML 元件達到下載效果
function downloadURI(uri, name) {
var link = document.createElement("a");
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
2016年6月7日 星期二
操作 ng-repeat 動態產生的物件
.directive("cardid", function () {
return {
link: function (scope, element) {
$(element).mask('9999999999999');
}
}
})
return {
link: function (scope, element) {
$(element).mask('9999999999999');
}
}
})
2016年6月6日 星期一
使用 MASKED INPUT PLUGIN 限制輸入
$(document).ready(function () {
$.mask.definitions['A'] = "[A-Za-z0-9]";
$("input[name=車號]").mask('AA?AA', { placeholder: '' }); // ? 後面表示選擇性
});
下載
ng-mdel 輸入自動轉大寫
.directive('uppercased', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function(input) {
return input ? input.toUpperCase() : "";
});
element.css("text-transform","uppercase");
}
};
})
input type="text" uppercased ng-model="id"
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function(input) {
return input ? input.toUpperCase() : "";
});
element.css("text-transform","uppercase");
}
};
})
input type="text" uppercased ng-model="id"
2016年5月26日 星期四
2016年5月7日 星期六
讓chrome 自動開啟檔案且不要下載
1. 設定檔案下載儲存位置為
C:\Users\%username%\AppData\Local\Google\Chrome\User Data\Default\Cache
2. 勾選"下載每個檔案前詢問儲存位置"
3. 針對不要下載的檔案類型於第一次下載後設定為自動開啟
C:\Users\%username%\AppData\Local\Google\Chrome\User Data\Default\Cache
2. 勾選"下載每個檔案前詢問儲存位置"
3. 針對不要下載的檔案類型於第一次下載後設定為自動開啟
2016年4月26日 星期二
2016年3月29日 星期二
表單驗證使用jquery.validate
設定錯誤訊息出現位置及樣式
label.error {
color: red;
position: absolute;
background-color: white;
padding: 0.25em;
border: 1px solid #adff2f;
}
$('#form1').validate({
errorPlacement: function (error, element) {
$(element).parent().append(error);
$(error).css({ top: $(element).position().top, left: $(element).position().left + $(element).width()+10 })
},
});
自訂錯誤訊息
<input name="id" minlength="4" data-msg-minlength="長度必須大於4">
自訂驗證規則
$.validator.addMethod("fixlength", function (value, element,param) {return !value || value.length == param;
}, jQuery.validator.format("長度必須為{0}"));
$("#form").validate();<input data-rule-fixlength='4' type="text">
依據條件驗證
$('#form1').validate({
rules: {
Mailbox: {
required: '#sendmail:checked',
email: '#sendmail:checked'
},
}
});
<input type="checkbox" id="sendmail" />Email:<input type="text" name="Mailbox" id="Mailbox" />
ag-grid 設定欄寬依內容自動調整,且設定最小寬度避免欄位名稱無法完整顯示
{ field: '廠商編號', headerName: '廠商編號', minWidth:80 },
$scope.gridOptions.api.setRowData(list);
$scope.gridOptions.columnApi.autoSizeColumns(Enumerable.From($scope.gridOptions.columnApi.getAllColumns()).Select('$.colId').ToArray());
* 使用 autoSizeColumns() 前必須讓 grid 為顯示狀態
$scope.gridOptions.api.setRowData(list);
$scope.gridOptions.columnApi.autoSizeColumns(Enumerable.From($scope.gridOptions.columnApi.getAllColumns()).Select('$.colId').ToArray());
* 使用 autoSizeColumns() 前必須讓 grid 為顯示狀態
2016年3月24日 星期四
2016年3月17日 星期四
ui bootstrap modal size 設定方式,包含內容區域填滿可用空間
javascript
====
.directive('modalbody', function ($timeout) { // 填滿可用空間
return {
link: function (scope, elem, attrs) {
var positioner = function () {
$(elem).closest('.modal-content').css('height', $(window).height() - 60);
$(elem).closest('.modal-dialog').css('width', $(window).width() - 60);
var h = $(elem).closest('.modal-content')[0].offsetHeight - $(elem).closest('.modal-content').find('.modal-header')[0].offsetHeight- $(elem).closest('.modal-content').find('.modal-footer')[0].offsetHeight;
if (attrs.modalbody) h += parseFloat(attrs.modalbody);
$(elem).outerHeight(h);
$(elem).find('.modal-body-inner').height($(elem).height());
}
$(window).resize(function () {
positioner();
});
$timeout(function () {
positioner();
});
}
};
})
html
====
<script type="text/ng-template" id="voucher.html">
====
.directive('modalbody', function ($timeout) { // 填滿可用空間
return {
link: function (scope, elem, attrs) {
var positioner = function () {
$(elem).closest('.modal-content').css('height', $(window).height() - 60);
$(elem).closest('.modal-dialog').css('width', $(window).width() - 60);
var h = $(elem).closest('.modal-content')[0].offsetHeight - $(elem).closest('.modal-content').find('.modal-header')[0].offsetHeight- $(elem).closest('.modal-content').find('.modal-footer')[0].offsetHeight;
if (attrs.modalbody) h += parseFloat(attrs.modalbody);
$(elem).outerHeight(h);
$(elem).find('.modal-body-inner').height($(elem).height());
}
$(window).resize(function () {
positioner();
});
$timeout(function () {
positioner();
});
}
};
})
.directive('modalbodymax', function ($timeout) { // 超過最大可用空間才限制
return {
link: function (scope, elem, attrs) {
var positioner = function () {
$(elem).closest('.modal-content').css('maxHeight', $(window).height() - 60);
$(elem).closest('.modal-content').css('maxWidth', $(window).width() - 60);
var maxh = $(window).height() - 60 * 2 - $(elem).closest('.modal-content').find('.modal-header').height() - $(elem).closest('.modal-content').find('.modal-footer').height();
$(elem).css('maxHeight', maxh);
}
$(window).resize(function () {
positioner();
});
$timeout(function () {
positioner();
});
}
};
})
html
====
<script type="text/ng-template" id="voucher.html">
<div class="modal-header "> <button class="close" ng-click="close()"><span class='glyphicon glyphicon-remove' style="font-size:40px"></span></button> <h3 class="modal-title">傳票明細</h3> </div>
<div class="modal-body" modalbody> <div ag-grid="gridOptions" class="ag-green modal-body-inner">
</div>
</div>
</script>
css
====
.modal-body-inner {
overflow-y: auto;
}
css
====
.modal-body-inner {
overflow-y: auto;
}
2016年3月15日 星期二
angularjs 與中文如何搭配
{{object.銷售}} <= 中文不ok
{{object["銷售"]}} <= 中文ok
ng-show="object['中文']==true" <= 中文不ok
ng-show='object["中文"]==true' <= 中文ok
{{object["銷售"]}} <= 中文ok
ng-show="object['中文']==true" <= 中文不ok
ng-show='object["中文"]==true' <= 中文ok
2016年3月12日 星期六
於 angularjs 中顯示圖片
<img style="width:100%" data-ng-src="data:image/png;base64,{{object['照片']}}">
若要更換圖片且圖片來源是透過 <input id="fileinput" class="form-control" type="file" fileread="$parent['上傳照片']" /> 取得,則必須去除前面自動產生的 "data:image/png;base64," 這種字串
$scope.object['照片']=$scope.上傳照片.split(',')[1];
若要更換圖片且圖片來源是透過 <input id="fileinput" class="form-control" type="file" fileread="$parent['上傳照片']" /> 取得,則必須去除前面自動產生的 "data:image/png;base64," 這種字串
$scope.object['照片']=$scope.上傳照片.split(',')[1];
2016年3月9日 星期三
json 轉換
c#
====
將 json 字串轉為物件
var list = JsonConvert.DeserializeObject<IEnumerable<Newtonsoft.Json.Linq.JObject>>(jsonlist);
foreach (var obj in list)
foreach (var p in obj.Properties())
obj.Value<int>(p.Name); //轉換為特定型態
obj.Value<dynamic>(p.Name); //不轉換型態
javascript
====
將物件轉為 json 字串 : JSON.stringify(jsonlist)
將 json 字串轉為物件 : JSON.parse(jsonstring)
範例 : 把前端物件陣列匯出成excel
c#
====
public string JsonExcel(string jsonlist, string 檔名)
{
var list = JsonConvert.DeserializeObject(jsonlist);
using (var ep = new OfficeOpenXml.ExcelPackage())
{
int row = 1, col = 1;
var ws = ep.Workbook.Worksheets.Add("工作表1");
if (list.Count()>0)
foreach (var p in list.FirstOrDefault().Properties())
ws.Cells[row, col++].Value = p.Name;
foreach (var obj in list)
{
row++;
col = 1;
foreach (var p in obj.Properties())
{
ws.Cells[row, col++].Value = obj.Value(p.Name).Value;
if (obj.Value(p.Name).Value is DateTime)
ws.Cells[row, col-1].Style.Numberformat.Format = "yyyy/MM/dd";
}
}
var fi = new System.IO.FileInfo(Server.MapPath("~") + "\\download\\{0}.xlsx".FormatString(檔名));
ep.SaveAs(fi);
string baseUrl = Request.Url.Scheme + "://" + Request.Url.Authority + Request.ApplicationPath.TrimEnd('/') + "/";
return baseUrl + "download/{0}.xlsx".FormatString(檔名);
}
}
javascript
====
$http.post('@Url.Action("JsonExcel")', { jsonlist: JSON.stringify($scope.gridOptions.rowData), 檔名: "總分類帳明細" })
.then(function (result) {
window.location = result.data;
});
====
將 json 字串轉為物件
var list = JsonConvert.DeserializeObject<IEnumerable<Newtonsoft.Json.Linq.JObject>>(jsonlist);
foreach (var obj in list)
foreach (var p in obj.Properties())
obj.
obj.Value<dynamic>(p.Name); //不轉換型態
javascript
====
將物件轉為 json 字串 : JSON.stringify(jsonlist)
將 json 字串轉為物件 : JSON.parse(jsonstring)
範例 : 把前端物件陣列匯出成excel
c#
====
public string JsonExcel(string jsonlist, string 檔名)
{
var list = JsonConvert.DeserializeObject
using (var ep = new OfficeOpenXml.ExcelPackage())
{
int row = 1, col = 1;
var ws = ep.Workbook.Worksheets.Add("工作表1");
if (list.Count()>0)
foreach (var p in list.FirstOrDefault().Properties())
ws.Cells[row, col++].Value = p.Name;
foreach (var obj in list)
{
row++;
col = 1;
foreach (var p in obj.Properties())
{
ws.Cells[row, col++].Value = obj.Value
if (obj.Value
ws.Cells[row, col-1].Style.Numberformat.Format = "yyyy/MM/dd";
}
}
var fi = new System.IO.FileInfo(Server.MapPath("~") + "\\download\\{0}.xlsx".FormatString(檔名));
ep.SaveAs(fi);
string baseUrl = Request.Url.Scheme + "://" + Request.Url.Authority + Request.ApplicationPath.TrimEnd('/') + "/";
return baseUrl + "download/{0}.xlsx".FormatString(檔名);
}
}
javascript
====
$http.post('@Url.Action("JsonExcel")', { jsonlist: JSON.stringify($scope.gridOptions.rowData), 檔名: "總分類帳明細" })
.then(function (result) {
window.location = result.data;
});
2016年3月8日 星期二
javascript 依照中文筆劃排序
array.sort(function(a,b){return a.localeCompare(b, "zh-Hant")})
切換排序方向並顯示箭頭
<div @click="排序('text');arrs=arrs.sort((a, b) => (a.text || '').localeCompare((b.text || ''), 'zh-Hant')*排序值)">
{{ arr.text }}
<div style="float:right" v-if="排序欄位=='text'"><span v-if="排序值==1">▲</span><span v-if="排序值==-1">▼</span></div>
</div>
const 排序 = (value) => {
const 切換欄位 = 排序欄位.value != value;
排序欄位.value = value;
if (!切換欄位) 排序值.value = 排序值.value == -1 ? 1 : -1;
}
多欄位排序
arrs.sort((a, b) => (a.text.localeCompare(b.text, 'zh-Hant')*10+(a.text2 || '').localeCompare((b.text2 || ''), 'zh-Hant'))*排序值)
2016年2月19日 星期五
linq.js - LINQ for JavaScript 使用範例
走訪物件
====
Enumerable.From(arr).Where(a=>a.voucherTime==null).ForEach(function (object) {
object.check = newValue;
});
找出物件陣列中的某個物件
====
Enumerable.From(arr).Where(a=>a.id===id).FirstOrDefault()
判斷字串陣列中是否包含某個字串
====
Enumerable.From(arr).Contains("ag-cell")
依據 key 替換物件
====
dic=Enumerable.From(arr).ToDictionary("$.id", "$"); // $ : 物件, $.id : 物件的key屬性
dic.Set(data.id,?); // 替換
arr=dic.ToEnumerable().Select("$.Value").ToArray(); // Dictionary 轉為 Enumerable 會是新物件集合,內含兩個屬性 key、value,$.Value 就是原本的物件
刪除某個物件
====
$scope.objects=Enumerable.From($scope.objects).Except([obj]).ToArray();
用函數作為條件
.Where(function (x) {return new Date(x.expireDate)>=$scope.fromDate || $scope.fromDate==null})
官方文件 (載點已掛)
使用範例:
====
Enumerable.From(arr).Where(a=>a.voucherTime==null).ForEach(function (object) {
object.check = newValue;
});
找出物件陣列中的某個物件
====
Enumerable.From(arr).Where(a=>a.id===id).FirstOrDefault()
判斷字串陣列中是否包含某個字串
====
Enumerable.From(arr).Contains("ag-cell")
依據 key 替換物件
====
dic=Enumerable.From(arr).ToDictionary("$.id", "$"); // $ : 物件, $.id : 物件的key屬性
dic.Set(data.id,?); // 替換
arr=dic.ToEnumerable().Select("$.Value").ToArray(); // Dictionary 轉為 Enumerable 會是新物件集合,內含兩個屬性 key、value,$.Value 就是原本的物件
刪除某個物件
====
$scope.objects=Enumerable.From($scope.objects).Except([obj]).ToArray();
用函數作為條件
.Where(function (x) {return new Date(x.expireDate)>=$scope.fromDate || $scope.fromDate==null})
官方文件 (載點已掛)
載入方式:
import Enumerable from '../../../scripts/linq1.min.js';
使用範例:
Enumerable.from(xxx)
.where(a => a.xxx==ooo)
.groupBy(a => a.xxx)
.orderBy(a => a.key())
.select(a => ({ name: a.first().xxx, cnt: a.sum(b => b.xxx)})).select(a => `${a.name}: ${a.cnt}`)
.toJoinedString(', ')
2016年1月27日 星期三
jquery $.ajax 呼叫失敗
chrome console 出現這類錯誤 : POST http://localhost:9032/webservice1.asmx/GetActivitys 500 (Internal Server Error)
觀察server 事件檢視器會發現更明確的警告 :
Exception type: ArgumentOutOfRangeException
Exception message: 在多位元組的目的字碼頁中,沒有這個 Unicode 字元可以對應到的字元。 (發生例外狀況於 HRESULT: 0x80070459)
爬文得知是因為 cookie 中包含中文,會影響 jquery 的 $.ajax 功能
結論 : cookie 請勿使用中文,不管是 name 還是 value 都不行
觀察server 事件檢視器會發現更明確的警告 :
Exception type: ArgumentOutOfRangeException
Exception message: 在多位元組的目的字碼頁中,沒有這個 Unicode 字元可以對應到的字元。 (發生例外狀況於 HRESULT: 0x80070459)
爬文得知是因為 cookie 中包含中文,會影響 jquery 的 $.ajax 功能
結論 : cookie 請勿使用中文,不管是 name 還是 value 都不行
2016年1月21日 星期四
angularjs 正確顯示 html
javascript
====
controller 注入 $sce
透過 $sce.trustAsHtml() 得到可以正確顯示的內容
html
====
<span ng-bind-html='content'></span>
====
controller 注入 $sce
透過 $sce.trustAsHtml() 得到可以正確顯示的內容
html
====
<span ng-bind-html='content'></span>
2016年1月18日 星期一
ag-grid 使用範例
//宣告
agGrid.initialiseAgGridWithAngular1(angular);
angular.module('module1', ['agGrid']).controller('ctrl1', function ($scope, $http, $filter) {
//初始設定
$scope.gridOptions = {
enableFilter: true, floatingFilter: true, suppressMenu: true, // 加入即時篩選方塊
suppressMovableColumns: true,
angularCompileRows: true,
rowSelection: 'single',
enableColResize: true,
enableSorting: true,
onCellFocused: function (event) {
if ($scope.gridOptions.api.getModel().rowsToDisplay[event.rowIndex]) $scope.gridOptions.api.getModel().rowsToDisplay[event.rowIndex].setSelected(true);
}, // 使用鍵盤方向鍵自動選取列
defaultColDef: {
suppressMenu: true, floatingFilterComponentParams: { suppressFilterButton: true } // 使用即時篩選方塊時隱藏不要顯示的物件
},
columnDefs: [
{
headerName: '日期', width: 100, cellStyle: { 'text-align': 'center'}, cellRenderer: function (params) {
return $filter('date')(new Date(params.value), 'yyyy/MM/dd');
},filter: 'agTextColumnFilter', filterParams: {
textCustomComparator: function (filter, value, filterText) {
var datestring = $filter('date')(new Date(value), 'yyyyMMdd');
return datestring.indexOf(filterText) >= 0;
}, // 日期篩選要透過客製化達成
}
},
※ 避免在 cellRenderer 中執行非 return 指令,避免畫面無法自動更新而必須透過 redrawrows 引發其他問題
//寫入資料
$scope.getlist = function () {
$http.post('@Url.Action("查詢")', { fromdate: $scope.fromdate, todate: $scope.todate })
.then(function (result) {
$scope.gridOptions.api.setRowData(result.data);
}).catch(function (data) {
if (data.status != '') alert(data.statusText);
else alert('發生錯誤,請重新整理頁面後再試一次');
console.log(data.data);
});
};
//html
<script type="text/javascript" src="~/scripts/ag-grid.min.js"></script>
<link href="~/Content/ag-grid.min.css" rel="stylesheet" type="text/css" />
<link href="~/Content/theme-fresh.min.css" rel="stylesheet" type="text/css" />
<div id="divlist" ag-grid="gridOptions" class="ag-fresh" ng-style="getTableHeight()"></div>
//css
讓 form-control 佔滿全部寬度
.ag-cell > span {
width: 100%;
}
避免cell使用 div 內含<br>時造成空隙太大
.ag-cell {
line-height: unset !important;
}
垂直置中 (有設定高度會需要)
.ag-cell {
display: flex !important;align-items: center;
}
.ag-header-cell-label {
width: 100% !important; // 避免欄位名稱要設定很寬否則顯示不完全而出現...
justify-content: center; // 置中
}
欄位左右間距調整
.ag-header-cell, .ag-header-group-cell, .ag-cell {
padding-left: 5px;
padding-right: 5px;
}
不要強制設定字型
點選欄位不要出現外框
agGrid.initialiseAgGridWithAngular1(angular);
angular.module('module1', ['agGrid']).controller('ctrl1', function ($scope, $http, $filter) {
//初始設定
$scope.gridOptions = {
enableFilter: true, floatingFilter: true, suppressMenu: true, // 加入即時篩選方塊
suppressMovableColumns: true,
angularCompileRows: true,
rowSelection: 'single',
enableColResize: true,
enableSorting: true,
onCellFocused: function (event) {
if ($scope.gridOptions.api.getModel().rowsToDisplay[event.rowIndex]) $scope.gridOptions.api.getModel().rowsToDisplay[event.rowIndex].setSelected(true);
}, // 使用鍵盤方向鍵自動選取列
defaultColDef: {
suppressMenu: true, floatingFilterComponentParams: { suppressFilterButton: true } // 使用即時篩選方塊時隱藏不要顯示的物件
},
columnDefs: [
{
headerName: '日期', width: 100, cellStyle: { 'text-align': 'center'}, cellRenderer: function (params) {
return $filter('date')(new Date(params.value), 'yyyy/MM/dd');
},filter: 'agTextColumnFilter', filterParams: {
textCustomComparator: function (filter, value, filterText) {
var datestring = $filter('date')(new Date(value), 'yyyyMMdd');
return datestring.indexOf(filterText) >= 0;
}, // 日期篩選要透過客製化達成
}
},
※ 避免在 cellRenderer 中執行非 return 指令,避免畫面無法自動更新而必須透過 redrawrows 引發其他問題
//寫入資料
$scope.getlist = function () {
$http.post('@Url.Action("查詢")', { fromdate: $scope.fromdate, todate: $scope.todate })
.then(function (result) {
$scope.gridOptions.api.setRowData(result.data);
}).catch(function (data) {
if (data.status != '') alert(data.statusText);
else alert('發生錯誤,請重新整理頁面後再試一次');
console.log(data.data);
});
};
//html
<script type="text/javascript" src="~/scripts/ag-grid.min.js"></script>
<link href="~/Content/ag-grid.min.css" rel="stylesheet" type="text/css" />
<link href="~/Content/theme-fresh.min.css" rel="stylesheet" type="text/css" />
<div id="divlist" ag-grid="gridOptions" class="ag-fresh" ng-style="getTableHeight()"></div>
//css
讓 form-control 佔滿全部寬度
.ag-cell > span {
width: 100%;
}
避免cell使用 div 內含<br>時造成空隙太大
.ag-cell {
line-height: unset !important;
}
垂直置中 (有設定高度會需要)
.ag-cell {
display: flex !important;align-items: center;
}
.ag-header-cell-label {
width: 100% !important; // 避免欄位名稱要設定很寬否則顯示不完全而出現...
justify-content: center; // 置中
}
欄位左右間距調整
.ag-header-cell, .ag-header-group-cell, .ag-cell {
padding-left: 5px;
padding-right: 5px;
}
不要強制設定字型
.ag-theme-balham,.ag-header {
font-size: unset !important;
}
點選欄位不要出現外框
.ag-cell-focus {
border: unset;
}
若用到 display: flex,且未使用cellRenderer,則水平靠右對齊方式改為
cellStyle: { 'justify-content': 'flex-end' }
計算筆數
$scope.gridOptions.api.getDisplayedRowCount(); // 篩選後筆數
$scope.gridOptions.api.getModel().rootNode.allLeafChildren.length; // 完整筆數
若用到 display: flex,且未使用cellRenderer,則水平靠右對齊方式改為
cellStyle: { 'justify-content': 'flex-end' }
計算筆數
$scope.gridOptions.api.getDisplayedRowCount(); // 篩選後筆數
$scope.gridOptions.api.getModel().rootNode.allLeafChildren.length; // 完整筆數
取得nodes (不要直接抓 rowData)
$scope.gridOptions.api.getModel().rowsToDisplay
Enumerable.From($scope.gridOptions.api.getModel().rowsToDisplay).Select('$.data').ToArray(); // 取data
若 cellRenderer 使用 {{}} 顯示內容,有些情況會造成沒有確實轉換,此時可以透過以下方式解決
$timeout(function () {
if (!$scope.$$phase) $scope.$apply();
}, 100);
載入資料後某欄位沒有任何資料則不顯示避免無用欄位太多
Enumerable.From($scope.gridOptions.columnDefs).ForEach(function (col) {
$scope.gridOptions.columnApi.setColumnVisible(col.field, Enumerable.From($scope.gridOptions.rowData).Any('$.'+col.field+''));
});
排序依照中文筆畫
{ field: '名稱', headerName: '名稱', comparator: textComparator },
function textComparator(a, b, d1, d2, isInverted) {
return a.localeCompare(b, "zh-Hant");
}
避免凍結欄位時出現捲軸
.ag-pinned-left-cols-viewport {
overflow-y: hidden !important;
}
Enumerable.From($scope.gridOptions.api.getModel().rowsToDisplay).Select('$.data').ToArray(); // 取data
若 cellRenderer 使用 {{}} 顯示內容,有些情況會造成沒有確實轉換,此時可以透過以下方式解決
$timeout(function () {
if (!$scope.$$phase) $scope.$apply();
}, 100);
載入資料後某欄位沒有任何資料則不顯示避免無用欄位太多
Enumerable.From($scope.gridOptions.columnDefs).ForEach(function (col) {
$scope.gridOptions.columnApi.setColumnVisible(col.field, Enumerable.From($scope.gridOptions.rowData).Any('$.'+col.field+''));
});
排序依照中文筆畫
{ field: '名稱', headerName: '名稱', comparator: textComparator },
function textComparator(a, b, d1, d2, isInverted) {
return a.localeCompare(b, "zh-Hant");
}
避免凍結欄位時出現捲軸
.ag-pinned-left-cols-viewport {
overflow-y: hidden !important;
}
2016年1月5日 星期二
取得 webapp 網址根路徑
Request.Url.Scheme + "://" + Request.Url.Authority + Request.ApplicationPath.TrimEnd('/') + "/"
於 angularjs 中下載及上傳檔案的方式 (支援多個檔案上傳)
1. server 產生檔案並下載 (epplus 為例)
c#
====
using (var ep = new OfficeOpenXml.ExcelPackage())
{
...
ep.Save();
return File((ep.Stream as System.IO.MemoryStream).ToArray(), "application/octet-stream");
}
javascript
====
$http({
url: urlBase + '/download',
method: "POST",
responseType: "blob",
data: { },
})
.then(function (result) {
downloadBlob(result.data, 'aaa.xlsx');
});
function downloadBlob(blob, name) {
if (ismobile()) { // iphone 無法使用 blob 下載,須轉為base64(上限2MB 且必須使用內建瀏覽器否則檔名會不正確)
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function () {
var base64data = reader.result;
var link = document.createElement("a");
link.download = name;
link.href = base64data;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
} else {
var link = document.createElement("a");
var url = URL.createObjectURL(blob);
link.download = name;
link.href = url;
document.body.appendChild(link);
link.onclick = function () {
requestAnimationFrame(function () {
URL.revokeObjectURL(url);
document.body.removeChild(link);
delete link;
})
};
link.click();
}
}
2. 上傳後下載
html
====
<input type="file" fileread="file" /> // 單一檔案上傳
<input type="file" multiple filesread="files" /> // 多重檔案上傳
javascript
====
$http.post('...', { filename: $scope.file.name,filecontent:$scope.file.value} // 單一檔案上傳
$http.post('...', { files: $scope.files} // 多重檔案上傳
c#
====
using (var ep = new OfficeOpenXml.ExcelPackage())
{
...
ep.Save();
return File((ep.Stream as System.IO.MemoryStream).ToArray(), "application/octet-stream");
}
javascript
====
$http({
url: urlBase + '/download',
method: "POST",
responseType: "blob",
data: { },
})
.then(function (result) {
downloadBlob(result.data, 'aaa.xlsx');
});
function downloadBlob(blob, name) {
if (ismobile()) { // iphone 無法使用 blob 下載,須轉為base64(上限2MB 且必須使用內建瀏覽器否則檔名會不正確)
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function () {
var base64data = reader.result;
var link = document.createElement("a");
link.download = name;
link.href = base64data;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
} else {
var link = document.createElement("a");
var url = URL.createObjectURL(blob);
link.download = name;
link.href = url;
document.body.appendChild(link);
link.onclick = function () {
requestAnimationFrame(function () {
URL.revokeObjectURL(url);
document.body.removeChild(link);
delete link;
})
};
link.click();
}
}
2. 上傳後下載
html
====
<input type="file" fileread="file" /> // 單一檔案上傳
<input type="file" multiple filesread="files" /> // 多重檔案上傳
javascript
====
$http.post('...', { filename: $scope.file.name,filecontent:$scope.file.value} // 單一檔案上傳
$http.post('...', { files: $scope.files} // 多重檔案上傳
).then(function (result) {
$('input[type=file]').val(''); // 清空選擇檔案內容
return {
scope: {
filesread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
scope.filesread = [];
Enumerable.From(changeEvent.target.files).ForEach(file => {
var reader = new FileReader();
var filename = file.name;
reader.onload = function (loadEvent) {
scope.$apply(function () { // $apply可確保真的更新,否則必須畫面有變化才會更新
scope.filesread.push({ name: filename, value: loadEvent.target.result }); // 對應到$scope.files
});
}
reader.readAsDataURL(file);
});
});
}
}
}])
c#
====
public class 檔案
{
public string name { get; set; }
public string value { get; set; }
}
public void 上傳(IEnumerable<檔案> files) {
var bytes = System.Text.Encoding.ASCII.GetBytes(檔案.value);
db.上傳檔案.Add(new 上傳檔案() { 檔案內容 = bytes, 檔名 = 檔案.name });
}
public string 下載檔案(int id)
{
var model = db.上傳檔案.Find(id);
return JsonConvert.SerializeObject(new { model.檔名, 檔案內容 = System.Text.Encoding.ASCII.GetString(model.檔案內容) });
}
javascript
====
$scope.download = function (id) {
$http.post(urlBase + '/下載檔案', { id: id }).then(function (result) {
downloadURI(result.data.檔案內容, result.data.檔名);
});
}
function downloadURI(dataURI, name) {
var link = document.createElement("a");
if (ismobile()) { // iphone 無法使用 blob 下載 (此寫法上限2MB 且必須使用內建瀏覽器否則檔名會不正確)
link.download = name;
link.href = dataURI;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
else {
var blob = dataURIToBlob(dataURI);
var url = URL.createObjectURL(blob);
link.download = name;
link.href = url;
document.body.appendChild(link);
link.onclick = function () {
requestAnimationFrame(function () {
URL.revokeObjectURL(url);
document.body.removeChild(link);
delete link;
})
};
link.click();
}
}
function dataURIToBlob(dataURI) {
var binStr = atob(dataURI.split(',')[1]),
len = binStr.length,
arr = new Uint8Array(len),
mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
for (var i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
return new Blob([arr], {
type: mimeString
});
}
directive("fileread", [function () { // 單一檔案上傳
return {
scope: {
fileread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
var reader = new FileReader();
var filename = changeEvent.target.files[0].name;
reader.onload = function (loadEvent) {
scope.$apply(function () {
scope.fileread = { value: loadEvent.target.result, name: filename}; // 對應到$scope.file
});
}
reader.readAsDataURL(changeEvent.target.files[0]);
});
}
}
}])
directive("filesread", [function () { // 多重檔案上傳return {
scope: {
filesread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
scope.filesread = [];
Enumerable.From(changeEvent.target.files).ForEach(file => {
var reader = new FileReader();
var filename = file.name;
reader.onload = function (loadEvent) {
scope.$apply(function () { // $apply可確保真的更新,否則必須畫面有變化才會更新
scope.filesread.push({ name: filename, value: loadEvent.target.result }); // 對應到$scope.files
});
}
reader.readAsDataURL(file);
});
});
}
}
}])
c#
====
public class 檔案
{
public string name { get; set; }
public string value { get; set; }
}
public void 上傳(IEnumerable<檔案> files) {
foreach (var 檔案 in files)
{var bytes = System.Text.Encoding.ASCII.GetBytes(檔案.value);
db.上傳檔案.Add(new 上傳檔案() { 檔案內容 = bytes, 檔名 = 檔案.name });
}
public string 下載檔案(int id)
{
var model = db.上傳檔案.Find(id);
return JsonConvert.SerializeObject(new { model.檔名, 檔案內容 = System.Text.Encoding.ASCII.GetString(model.檔案內容) });
}
javascript
====
$scope.download = function (id) {
$http.post(urlBase + '/下載檔案', { id: id }).then(function (result) {
downloadURI(result.data.檔案內容, result.data.檔名);
});
}
function downloadURI(dataURI, name) {
var link = document.createElement("a");
if (ismobile()) { // iphone 無法使用 blob 下載 (此寫法上限2MB 且必須使用內建瀏覽器否則檔名會不正確)
link.download = name;
link.href = dataURI;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
else {
var blob = dataURIToBlob(dataURI);
var url = URL.createObjectURL(blob);
link.download = name;
link.href = url;
document.body.appendChild(link);
link.onclick = function () {
requestAnimationFrame(function () {
URL.revokeObjectURL(url);
document.body.removeChild(link);
delete link;
})
};
link.click();
}
}
function dataURIToBlob(dataURI) {
var binStr = atob(dataURI.split(',')[1]),
len = binStr.length,
arr = new Uint8Array(len),
mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
for (var i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
return new Blob([arr], {
type: mimeString
});
}
訂閱:
文章 (Atom)
input 連結 datalist 用程式控制彈出選項
範例: nextTick(() => document.querySelector('input').showPicker()); ※僅支援現代瀏覽器
-
1. 設定檔案下載儲存位置為 C:\Users\%username%\AppData\Local\Google\Chrome\User Data\Default\Cache 2. 勾選"下載每個檔案前詢問儲存位置" 3. 針對不要下載的檔案類型於第一...
-
自動設定欄寬 sheet.Cells.AutoFitColumns(3, 20); // 必須設定 min 跟 max 才會正常作用 凍結欄位 sheet.View.FreezePanes(4, 4); 標題列 ws.PrinterSettings.RepeatRo...
-
使用 FreeSpire.XLS ... ep.Save(); using (var workbook = new Workbook()) using (var memStream = new MemoryStream()) { workbook.LoadFromSt...