Angular裡面有一個方法可以把# (hash tag) 給拿掉,那就是將html5mode開啟

1
2
3
$locationProvider.html5Mode(true).hashPrefix('!')

// 這應該會要求設定<base href="/">

但是如果angular route是架構在asp.net mvc上面,那就會有route打架的情形發生, 或著reload page會出現頁面錯誤的訊息 網路上面的資訊也有很多種版本,以下我也提供一下我的版本

主要重點, asp.net的routeConfig裡面也要同時間定義angular route的部份,但是controller/action是指到index page

1
2
3
4
routes.MapRoute("member_edit",
"member/edit/{.Catchall}",
new { controller = "Home", action = "Index" },
namespaces: new[] { "Demo.Areas.member.Controllers" });
1
2
3
4
5
6
7
8
9
10
.state('main.edit', {
url: 'edit/:id',
views: {
'list@main': {
controller: 'editFavorController',
controllerAs: 'vm',
templateUrl: 'Home/EditFavor'
}
}
})

這樣子的設定, 可以讓其他頁面直接用網址的方式開啟那個頁面(請搜尋 deep link angualr)

當設定完成後,卻又發現另外一個問題,問題是, 我在選單連結的部份,有一些是要跑mvc本身的actionlink的動作, 但是angular會先處理 < a > 的動作,所以要跳過這個動作,可以利用 window.location.replace 來處理

今天在檢查一段程式的時候,再跑一段根據array的資料新增或更新到資料庫中,卻發現都是更新同一筆紀錄 原本的寫法

1
2
3
4
5
6
for(var i=0; i < arr.length; i++){
db.insert(xxx).then(function(){
...
all insert the same record
})
}

這是因為javascript async non-blocking的關係,所以資料庫新增自己跑自己的,for迴圈跑自己的,當新增時要取資料庫裡面資料時,會取到不對的值

解法:用array.forEach來替代for loop

1
2
3
4
5
arr.forEach(function(item,idx){
db.insert(xxx).then(function(){
...
})
});

當我改寫成這樣子後,就正常了

Reference Website Url http://happyfunpartytime.com/2012/11/azure-storage-2-0-some-blob-changes-to-be-aware-of/

大綱:

如果從官網上面抄下來的範例如果直接貼在vs裡面,會出現錯誤,那根據原本字面上的意思來找相類似的method來用

1
CloudBlob thumbnailBlob = objContainer.GetBlobReference(filename);

換成

1
var thumbnailBlob = objContainer.GetBlobReferenceFromServer(filename);

結果,一直給我跑404.

這GetBlobReserenceFromServer的用意是去server上面找filename的blob reference回來. 所以當我們要建立新的blob, 這就文不對題了。 所以要改用

1
CloudBlockBlob blob = objContainer).GetBlockBlobReference(filename);

這樣子就okey了.

1
blob.UploadFile(fileData.LocalFileName);


這個也改掉了, 要改成

1
CloudBlockBlob.UploadFromFile(filenameWithPath, FileMode)

CloudBlockBlob也有提供不同的上傳方式,請參閱MSDN

使用Azure新的NoSQL – DocumentDB(還在preview版本中)

怎們建立網頁上面有說. 這裡只記錄一些操作上的動作

  • DocumentDB裡面有分幾個元素 Database, DocumentCollection, document

元素之間的關係

1
2
3
4
5
6
Database -> DocumentCollection(with id name=xxxx)  -> document(s)
-> DocumentCollection(with id name=xxxx) -> document(s)
```

* 檢查database是否已存在

string dataBaseName = 「testDB」; var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey);

var database = client.CreateDatabaseQuery().FirstOrDefault(db => db.Id == dataBaseName);

if (database == null) { database = await client.CreateDatabaseAsync( new Database { Id = dataBaseName }); }

1
2
## 這個寫法如果用在webapi上面,會有出現等不到回應的情形發生,所以解決方法是變成同步, 寫法會變成

database = client.CreateDatabaseAsync(new Database{Id = dataBaseName}).Result;

1
2
3
4
5
6
7
8
9
10
11
12
13
14

* 檢查DocumentCollection是否已經建立

從上面知道如果要檢查Database是否已經建立, 要利用CreateDatabaseQuery(),
同樣的, 如果要檢查Document是否已經建立, 就要用 CreateDocumentCollectionQuery(database.CollectionsLink)

[MSDN -- DocumentServiceQueryable.CreateDatabaseQuery](http://msdn.microsoft.com/en-us/library/azure/microsoft.azure.documents.linq.documentservicequeryable.createdatabasequery.aspx)

[MSDN -- DocumentServiceQueryable.CreateDocumentCollectionQuery Method](http://msdn.microsoft.com/en-us/library/azure/microsoft.azure.documents.linq.documentservicequeryable.createdocumentcollectionquery.aspx)

* 建立Document

new a class object and save into DocumentCollection

User _user = new User(){name=『abc』}; var document1 = await client.CreateDocumentAsync(documentCollectionLink, _user);

這裡的documentCollectionLink是指 DocumentCollection collection = client.CreateDocumentCollectionQuery(database.SelfLink).FirstOrDefault(db => db.Id == dataBaseName); 或者是剛新增出來的collection DocumentCollection collection = client.CreateDocumentCollectionAsync(database.SelfLink, new DocumentCollection { Id = 「some name」 });

documentCollectionLink = collection.SelfLink;

1
2
3

* 更新Document

var doc = Client.CreateDocumentQuery(Favorscollection.DocumentsLink) .Where(d => d.Id == id) .AsEnumerable() .FirstOrDefault();

return Client.ReplaceDocumentAsync(doc.SelfLink, item);

1
2
3

* 刪除Document

var doc = Client.CreateDocumentQuery(Favorscollection.DocumentsLink) .Where(d => d.Id == id) .AsEnumerable() .FirstOrDefault();

return Client.DeleteDocumentAsync(doc.SelfLink);

1
2
3
4
5
6
7

* 查詢Document

可以用Linq的語法來做查詢或是用sql的語法也可以

[[DOC] Query DocumentDB](http://azure.microsoft.com/zh-tw/documentation/articles/documentdb-sql-query/)

Client.CreateDocumentQuery(Favorscollection.DocumentsLink) .Where(m => m.lastName == 「xxxx」) .ToList()


When move file in ngCordova or Cordova, it will need 2 plugins.

  1. cordova plugin add org.apache.cordova.file
  2. cordova plugin add org.apache.cordova.file-transfer

basic usage.

1
2
3
4
5
6
7
$cordovaFile.downloadFile(source, filepath, true, {}).then(function(result) {
// Success!
}, function(err) {
// Error
}, function(progress) {
// constant progress updates
});

it’s same as

1
2
3
4
5
6
7
8
9
10
var fileTransfer = new FileTransfer();
var uri = encodeURI(source);
fileTransfer.download(uri,filePath,
function (entry) {
// success
},
function (error) {
// error
},
trustAllHosts, options);

if you want to use it with $cordovaCamera.getPicture(), you will need to resolve FILE_URI first, and use it as source.

1
2
3
4
5
6
7
8
9
function getImageFileName(image) {
window.resolveLocalFileSystemURL(image,
function(entry) {
var uri = entry.toURL();
entry.file(function(file) {
var fileName = file.name;
});
});
}

API Document#File Entry

another problem is filepath. basePath can find it by below code. and filepath need a filename at the end.

1
2
3
4
5
6
$cordovaFile.createDir(directory, false).then(function(entry) {
// Success!
alert(entry.toURL());
}, function(err) {
// An error occured. Show a message to the user
});

今天在將資料庫搬到Azure的環境上面,然後遇到了一個選擇的困擾. 原本SQL Azure的規格有兩種. Web和Business 新的規格有三種Basic, Standard, Premium. 相關的規格說明請參閱http://azure.microsoft.com/zh-tw/pricing/details/sql-database/

所以我就先試試看Basic方案,結果:速度一個慢, 但是比Web規格便宜 (真的不建議使用,用這個不如用S0) Web的速度只有Premium 2可以跟的上, 價錢就是一個不可思議

那S0呢? 我嘗試後的結果是在可以接受的範圍內。但是價錢比Web貴了一點. 之後的規格,基本上就是價錢決定效能。

那我又想說如果自己用VM架設sql server呢…哈, 更貴. Orz. 直接放棄不考慮

最後只好還是繼續用要被淘汰的Web規格。然後抱著希望說等明年Web規格退休後,Azure可以提供更優價錢可以接受的選項。

angular在寫ng-repeat的時後, 因為想要利用 filter的功能將過濾後的資料集拿到不同區塊使用, 把function 寫到ng-repeat裡面。 像是

1
ng-repeat="item in processData((items | filter: someCondition))"

這一個粗心的錯誤會讓angular產生Error: error:infdig,Infinite $digest Loop的錯誤訊息

這個訊息的產生原因是當ng-repeat每跑一次, 會觸發processData fuction => 因為值改變,所以又會觸發$digest. 然後當$digest的次數太多之後,就會發生錯誤訊息, 執行效率也會變得非常的不好。

所以回到angularjs的頁面裡找到這個https://docs.angularjs.org/error/$rootScope/infdig

下面的說明就有提到這個現象.

Since getUsers() returns a new array, Angular determines that the model is different on each $digest cycle, resulting in the error. The solution is to return the same array object if the elements have not changed:

解決的方式就是不要在ng-repeat裡面寫function. 但如果要達到相同的效果, 可以先將過濾後的結果存到一個變數中, 然後在去操作那個變數就不會產生這個錯誤了

1
ng-repeat="item in (someVar = items | filter: someCondition)"

文章參考: http://www.hanselman.com/blog/IntroducingGulpGruntBowerAndNpmSupportForVisualStudio.aspx

需要條件 VS2013 update 3 installed

Visual Studio Extension

  1. [TRX - Task Runner Explorer](TRX - Task Runner Explorer)
  2. NPM/NBower Package Intellisense : Search for online NPM and Bower packages directly with Intellisense
  3. Grunt Launcher

操作方式: 請參考 http://www.hanselman.com/blog/IntroducingGulpGruntBowerAndNpmSupportForVisualStudio.aspx

好處:

不用再開一個command window 來跑grunt or gulp command, 所有的動作可以在VS裡面完成了 VS2013對於前端網頁的開發支援程度愈來越好了

1
2
ODataHttpRequestMessageExtensions.GetNextPageLink 和 
ODataHttpRequestMessageExtensions.GetInlineCount 都過時了..

要改用

1
2
Request.ODataProperties().NextLink,
Request.ODataProperties().TotalCount

ODataProperties 需要使用 System.Web.Http.OData.ExtensionsSystem.Web.OData.Extensions 命名空間