2018年12月21日 星期五

ui-select 複選用法

html
====
<ui-select multiple ng-model="filterStatus.selecteds"><ui-select-match placeholder="狀態過濾...">{{$item.text}}</ui-select-match><ui-select-choices repeat="obj in filterStatuss | filter: {text: $select.search} track by obj.value">{{obj.desc}}</ui-select-choices></ui-select>

javascript
====
$scope.filterStatuss = [{ value: 1, text: '未建立', desc: '未建立完畢' }, { value: 2, text: '未認款', desc: '已建立未認款' }, { value: 3, text: '未報件', desc: '已認款未報件' }];
$scope.filterStatus = { selecteds: [] };

※取值 => Enumerable.From($scope.filterStatus.selecteds).Select('$.value').ToArray();

css
====
.ui-select-match .btn-xs {
    font-size: unset;  // 選取按鈕字不要變小
}

.ui-select-multiple .ui-select-search {
    width: 30px !important; // 避免點選區域太寬
}

 .ui-select-multiple.ui-select-bootstrap input.ui-select-search {
    background-color:  lightgoldenrodyellow !important; // 設定點選區域底色
}

.ui-select-match .btn { // 已選取按鈕內間距調整
    opacity: unset;
    padding: 4px;
}

.ui-select-match-close {
    margin-right: -5px;  //  已選取按鈕X位置調整
}

2018年12月14日 星期五

ui-select 於 $uibModal 中正確顯示下拉選單

append-to-body="false"

若遇到被其他物件遮住的問題,則改用以下方法
append-to-body="true" style="z-index:9999;"

ui-select 調整下拉選單寬度和位置

.ui-select-bootstrap > .ui-select-choices, .ui-select-bootstrap > .ui-select-no-choice {
    width: unset; // 依據內容最大寬度決定
    left: unset; // 避免左邊界從下拉選單位置開始
    right: -80px; // 靠右
}


2018年12月13日 星期四

取得目前網址

目前動作網址 => Request.Url.AbsoluteUri.TrimEnd(Request.Url.Query);
目前預設動作網址 => Request.Url.Scheme + "://" + Request.Url.Authority +  Url.Action("Index");

自訂驗證規則

html
====
<input validator1 type='text' class='form-control' ng-model='uniform'><span style='color:red' ng-show="form1.$error.validator1">*</span>

javascript
====
directive("validator1", function () {
        return {
            restrict: 'A',
            require: "ngModel",
            link: function (scope, element, attributes, ngModel) {
                ngModel.$validators.validator1 = function (modelValue, viewValue) {
                    ... // return true or false
                }
            }
        };
    })

2018年11月30日 星期五

輸入欄位不要自動跳出建議

此問題因瀏覽器版本跟使用者電腦而異,所以同一個畫面同一個欄位有的人會遇到有的人不會

<input dont-fill type="tel" class="form-control" />

.directive('dontFill', function () {
        return {
            restrict: 'A',
            link: function link(scope, el, attrs) {
                // password fields need one of the same type above it (firefox)
                var type = el.attr('type') || 'text';
                // chrome tries to act smart by guessing on the name.. so replicate a shadow name
                var name = el.attr('name') || '';
                var shadowName = name + '_shadow';
                // trick the browsers to fill this innocent silhouette
                var shadowEl = angular.element('<input type="' + type + '" name="' + shadowName + '" style="display: none">');

                // insert before
                el.parent()[0].insertBefore(shadowEl[0], el[0]);
            }
        };
    })

2018年11月28日 星期三

entity framework transaction 用法

using (var scope = db.Database.BeginTransaction())
{
  ...
  db.SaveChanges();
  scope.Commit();
}

※ 跳出 exception 不須特別呼叫 Rollback()
※ 使用 TransactionScope 對同一個資料庫也會造成 msdtc 相關錯誤,不予採用

2018年11月22日 星期四

使用 LinqToExcel 讀取 csv

不支援 \t 分隔字元(其他未確認)
不支援unicode 編碼

寫法範例
System.IO.File.WriteAllText(FileName, System.IO.File.ReadAllText(FileName).Replace("\t", ","), System.Text.Encoding.Default)
var rows = new ExcelQueryFactory(FileName).WorksheetNoHeader(0)

2018年11月19日 星期一

使用 sessionStorage 針對同一分頁做資料交換

寫入
sessionStorage.setItem("公司id", $scope.companyid);

讀取
$scope.companyid = sessionStorage.getItem("公司id");

2018年11月8日 星期四

ui-select 於 ng-repeat 中綁定變數屬性方式

<div ng-repeat="a in list">
<ui-select append-to-body="true" ng-change="a['收件人id']=a['收件人物件'].value;" ng-model="a['收件人物件']">
                        <ui-select-match allow-clear="true">
                            <span ng-bind="$select.selected.text"></span>
                        </ui-select-match>
                        <ui-select-choices repeat="obj in employees | filter: $select.search track by $index">
                            <span ng-bind="obj.text"></span>
                        </ui-select-choices>
                    </ui-select>

因為ui-select ng-model 對應的是 repeat 中的元素,若該元素是物件,但希望改成對應ng-repeat物件某個屬性(收件人id),則需要另外用屬性物件(收件人物件)來轉換,且若考慮既有資料預設值,陣列元素也需要先設定好該屬性物件,以便正確顯示目前的選項

2018年11月2日 星期五

css 設定注意

1. class 優先權大於 type

.form-control {
width:auto;
}

table.詳細資料 select {
width:150px;
}

最後結果 select width 會是 auto
若要覆蓋.form-contrl 設定,需改成
table.詳細資料 select.form-control {
width:150px;
}

2. 若 select 使用多個class,多個class 優先權大於單一class

table.詳細資料 select.form-control.單位 {
width:100px;
}

最後結果 select width 會是 100px (優先權 :  select.form-control.單位 > select.form-control > .form-control)

3. 下面載入的 css 優先權大於上面載入,因此針對套件內建css 若要客製化,須把客製化css 放下面

2018年10月25日 星期四

create view 注意陷阱

若之後修改table 且把新欄位插入中間,且create view 的寫法是 select * from xxx,可能會造成欄位對應錯誤 (例如 select a as b,b as c from xxx),請將create view 改成列舉欄位名稱的寫法

2018年9月26日 星期三

2018年7月27日 星期五

table 加入搜尋機制且模擬瀏覽器 Ctrl+F 效果

模擬瀏覽器 Ctrl+F 效果 : highlight: JavaScript text higlighting jQuery plugin
下載 .js 後移除 "/* PLEASE DO NOT HOTLINK MY FILES, THANK YOU. */" 開始的內容,避免執行時出現一堆警告訊息

table 加入首列凍結效果 : StickyTableHeaders
配合尋找時可能會因為文字超出視窗範圍時自動捲動,讓首列(含尋找方塊)不要消失

javascript
====
$scope.styling = function () {
            $("table[name=Invoice]").stickyTableHeaders({ fixedOffset: $('.navbar') });
        };
$scope.$watch('searchInvoice', function (newValue, oldValue) {
            $('table[name=Invoice]').removeHighlight();
            if (newValue) $('table[name=Invoice]').highlight(newValue);
            $timeout(function () {
                if ($('table[name=Invoice] .highlight:first').length) {
                    var top = $(window).scrollTop();
                    var bottom = $(window).scrollTop() + $(window).height();
                    var elm_top = $('table[name=Invoice] .highlight:first').offset().top;
                    if (elm_top - top < 100) $(window).scrollTop(top - 100); // 100: navbar height
                    else if (elm_top > bottom - 25) $(window).scrollTop(elm_top - $(window).height() + 25); //25: text height
                }
                },500);
        });

html
====
<table name="Invoice" class="table table-condensed table-bordered table-hover" style="width:980px !important" ng-style="styling()">
                    <thead>
                        <tr class="warning">
                            <th style="width:80px">發票號碼</th>
                            <th style="width:80px">開立日期</th>
                            <th style="width:60px">金額</th>
                            <th style="width:40px">幣別</th>
                            <th style="width:80px">統一編號</th>
                            <th style="width:80px">買方</th>
                            <th style="width:80px">收件人</th>
                            <th style="width:300px">寄送地址</th>
                            <th style="width:80px">單號</th>
                            <th style="width:100px;background-color:unset;border-right:hidden;border-bottom:hidden;border-top:hidden"><input id="searchInvoice" type="text" placeholder="尋找發票..." style="width:100%" ng-model="searchInvoice" /></th>

2018年7月6日 星期五

引入 .js、.css、... 等靜態檔案時避免瀏覽器cache 造成更新後還是抓到舊版本

帶入隨時會變化的參數達到強制更新目的

.net core
<script type="text/javascript" src="~/scripts/common.js" asp-append-version="true"></script>

.net
方法1: 安裝 AspNet.Mvc.AssetVersioning 達到同樣效果 (實測無效,檔案內容不同version字串不會變,需確認是否用法問題)
方法2: <script src="~/Scripts/common.js?@DateTime.Now.ToShortTimeString()"></script>



epplus 用法

自動設定欄寬
sheet.Cells.AutoFitColumns(3, 20); // 必須設定 min 跟 max 才會正常作用

凍結欄位
sheet.View.FreezePanes(4, 4);

標題列
ws.PrinterSettings.RepeatRows = sheet.Cells["1:1"];

縮小成一頁寬
ws.PrinterSettings.FitToPage = true;
ws.PrinterSettings.FitToWidth = 1;
ws.PrinterSettings.FitToHeight = 0;

邊界
ws.PrinterSettings.LeftMargin = ws.PrinterSettings.TopMargin = ws.PrinterSettings.BottomMargin = ws.PrinterSettings.RightMargin = (decimal)0.3;

底色
sheet.Cells[row, 1, row, col - 1].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
sheet.Cells[row, 1, row, col - 1].Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.Yellow);

框線
range.Style.Border.Top.Style = range.Style.Border.Bottom.Style = range.Style.Border.Left.Style = range.Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;

小數格式
ws.Cells[row, 6].Style.Numberformat.Format = "0.00"; // 固定小數兩位
ws.Cells[row, 6].Style.Numberformat.Format = 整數不含小數點格式字串((decimal?)ws.Cells[row, 6].Value, "0.##"); // 若有小數則最多取兩位,若為整數則不含結尾的"."
string 整數不含小數點格式字串(decimal? value, string 格式字串)
        {
            if (格式字串 == null) return "";
            if (value == null) return 格式字串;
            if (value % 1 == 0 && 格式字串.IndexOf("0.#") > -1) return 格式字串.Substring(0, 格式字串.IndexOf("0.#") + 1);
            return 格式字串;
        }

插入列並保留格式
ws.InsertRow(rowindex, 1);
ws.Cells[rowindex-1, 1, rowindex-1, 最後欄index].Copy(ws.Cells[rowindex , 1, rowindex , 最後欄index]);

取得公式值
sheet.Cells[rowindex, colindex].FormulaR1C1="xxx";
sheet.Cells[rowindex, colindex].Calculate();
var 公式值 = sheet.Cells[rowindex, colindex].Value;

2018年5月30日 星期三

四捨五入且去除結尾的0及.

var a=2.335;
a.toMaxFixed(2) => "2.34"
a=2
a.toMaxFixed(2) => "2"
a=2.3
a.toMaxFixed(2) => "2.3"

Number.prototype.toMaxFixed = function (最大小數位) {
    return this.toFixed(最大小數位).replace(/0+$/, '').replace(/\.$/, '');
}

2018年5月8日 星期二

改善 SaveChanges() exception 顯示的錯誤訊息

擴充 .Context.cs 覆寫 SaveChanges() 顯示詳細的驗證錯誤訊息

1. 在Models資料夾底下新增資料夾,建議取名Extend
2. 新增class,檔名取相同名稱方便識別,如 Model1.Context.cs
3. 檔案範例內容如下
namespace xxx.Models
{
public partial class xxxEntities
    {
        public override int SaveChanges()
        {
            try
            {
                return base.SaveChanges();
            }
            catch (DbEntityValidationException ex)
            {
                // Retrieve the error messages as a list of strings.
                var errorMessages = ex.EntityValidationErrors
                        .SelectMany(x => x.ValidationErrors)
                        .Select(x => x.ErrorMessage);

                // Join the list to a single string.
                var fullErrorMessage = string.Join("; ", errorMessages);

                // Combine the original exception message with the new one.
                var exceptionMessage = string.Concat(ex.Message, "驗證錯誤訊息: ", fullErrorMessage);

                // Throw a new DbEntityValidationException with the improved exception message.
                throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
            }
        }
    }
}

參考來源

針對 entity framework core 已經沒有 DbEntityValidationException 需要換一種方式處理
try
{
return base.SaveChanges();
}
catch (DbUpdateException ex)
{
string err = "";
var failedEntries = ex.Entries;
foreach (var entry in failedEntries)
{
var entityName = entry.Metadata.Name;
var properties = entry.Properties.Where(p => p.IsModified && !p.IsTemporary);
foreach (var property in properties)
{
var propertyName = property.Metadata.Name;
err += $"\n更新欄位失敗: {entityName}.{propertyName}, 新值: {property.CurrentValue}";
}
}
throw new Exception(err,ex);
}

2018年4月16日 星期一

避免長時間的 select lock table 造成 insert or update blocking

啟用資料庫的讀取認可快照選項 (避免select lock)

ALTER DATABASE xxx SET READ_COMMITTED_SNAPSHOT ON

啟用資料庫的快照集隔離選項 (避免insert,update,delete lock)

ALTER DATABASE xxx SET ALLOW_SNAPSHOT_ISOLATION ON

進一步說明

啟用快照集隔離,可讀取交易啟動之前存在的資料,也就是前一個版本的資料,這會讓 insert 跟update 不至於 lock 造成 select blocking 問題,所以開啟此設定可以最大化降低 blocking,同時避免死結發生
使用 nolock 會讀取交易過程中的每次異動,但若交易取消,或最後認可的結果不是當時讀到的資料,則讀取的值就會是從未存在任一版本的 dirty data

2018年4月10日 星期二

利用 directive 動態設定 style

html
====
<div grid="-15"></div> /*設定增量為-15,因為下方要留空間塞其他物件*/

javascript
====
.directive('grid', function ($timeout) {
    return {
        link: function (scope, elem, attrs) {
            var setHeight = function () { /*設定高度填滿剩餘空間*/
                var h = $(window).height() - $(elem).offset().top - 10;
                if (attrs.grid) h += parseFloat(attrs.grid); /*考慮增量*/
                $(elem).height(h);
            }
            $(window).resize(function () { /*當視窗大小改變時再次設定高度*/
                setHeight();
            });
            $timeout(function () { /*使用 timeout 避免初次計算bug*/
                setHeight();
            });
        }
    };
})

2018年4月9日 星期一

server side 刪除 cookie

var c = new HttpCookie("xxx");
c.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(c);

2018年4月6日 星期五

使用 System.Linq.Dynamic 達成動態組合 linq 語法 (以 where 為例)

先使用 nuget 安裝 System.Linq.Dynamic

var name="YYY";

equal
var list=db.XXX.Where($"{name}==@0", 查詢值);

like
var list=db.XXX.Where($"{name}.Contains(@0)", 查詢值);

any
var list=db.XXX.Where($"{nameof(收款用途)}.Any({name}==@0)", 查詢值)

2018年3月20日 星期二

在 local 產生檔案

bower安裝 angular-file-saver
angular.module('module1', ['ngFileSaver',....]).controller('ctrl', function (FileSaver, Blob...
var data = new Blob([檔案字串], { type: 'text/plain;charset=utf-8' });
FileSaver.saveAs(data, "aaa.txt");


2018年2月9日 星期五

關閉 modal 造成 console 出現 error : Possibly unhandled rejection: undefined

var modalInstance = $uibModal.open({
...
modalInstance.result.then(function () {}, function () { }); <= 增加此列就不會出現error

2018年1月25日 星期四

javascript confirm 美化版 for angularjs

透過 bower 安裝 angular-confirm-modal

修改 .js 以便支援 html 語法 (如 <br />)
<div class="modal-body"><span ng-if="data.htmltext" ng-bind-html="data.htmltext"></span><span ng-if="data.text">{{data.text}}</span></div>

$confirm({ htmltext: $sce.trustAsHtml(result.data + "<br><br>是否繼續?"), title: "偵測到相同刷卡資料,請確認是否重複輸入", ok: '是', cancel: '否' })
                            .then(function () {
                               ... // 按ok才執行
                            });

2018年1月17日 星期三

iis 7.5 中設定應用程式集區識別身分ApplicationPoolIdentity的NTFS權限方式

應用程式集區預設識別身分為 ApplicationPoolIdentity ,是動態產生的使用者,若要在安全性中添加使用者,輸入格式為
IIS AppPool\[應用程式集區名稱]

2018年1月16日 星期二

ag-grid 更新部分資料方法

$scope.gridOptions.api.redrawRows({ rowNodes: [$scope.focusNode ] }); // 更新畫面部分node
$scope.gridOptions.api.redrawRows(); // 更新畫面所有node
$scope.gridOptions.api.updateRowData({ remove: [$scope.selectData] }); // 刪除資料
$scope.gridOptions.api.updateRowData({ add: result.data, addIndex: 0 }); // 加入資料
$scope.focusNode.setData($scope.selectData); // 資料內容異動更新回node(若有用到cellRenderer則不會重新render,還是要搭配redrawRows)

$scope.gridOptions = {
onCellFocused: function (event) {             
                $scope.focusNode = $scope.gridOptions.api.getModel().rowsToDisplay[event.rowIndex];
            },

PS. setData 不會再次觸發 checkboxSelection 自訂函數,需搭配 redrawRows
PS. redrawRows 會造成 focus 跑掉,若要設定setFocusedCell 必須放在下面執行
var firstCol = $scope.gridOptions.columnApi.getAllDisplayedColumns()[1];
$scope.gridOptions.api.setFocusedCell($scope.focusNode.rowIndex, firstCol);

2018年1月9日 星期二

c# 6&7 新特色

1. 使用 valuetuple 結構定義具備多個屬性的資料 (需透過 nuget 安裝package)
2. 函數中可以定義函數
3. 字串常數中可以置入物件 (取代 string.format)
4. 屬性及方法支援 lambda
5. 使用 nameof 動態取得屬性名稱 (避免hardcode)

ex:
class test {
string FirstName;
string LastName;
string FullName => $"{FirstName}{LastName}"; // 3,4
void func1() {
 (int Height, int Weight) GetHeightAndWeight() //1,2
            {
                var returnVal = (Height: 172, Weight: 80); //1
                return returnVal;
            }
            var aa = GetHeightAndWeight();
aa.Weight++;
var bb=$"{nameof(FirstName)}:{FirstName}"; //3,5
}
}

使用 visual studio 開啟網站類型的專案需額外安裝 package
1. Microsoft.CodeDom.Providers.DotNetCompilerPlatform
2. Microsoft.Net.Compilers
並修改 web.config
compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:7 <= 原本是6就會只支援 c# 6

input 連結 datalist 用程式控制彈出選項

範例: nextTick(() => document.querySelector('input').showPicker());  ※僅支援現代瀏覽器