Fixed a placeholder feature on IE (angularjs)

Placeholder要支援老舊的IE7~IE9,使用jQuery也都有一堆plugin可以使用了。如果要在angularjs上使用,但是又不想載入jQuery,這時候可以使用angularjs-placeholder module。

使用angularjs-placeholder

載入angular module:

1
<script type="text/javascript" src="../src/angularjs-placeholder.js"></script>

定義需要使用到的module,和初始化ng-app:

1
2
3
4
<script type="text/javascript">
var app = angular.module( "demoApp", ["html5.placeholder"] );
angular.bootstrap( document, [app.name] );
</script>

實作angularjs-placeholder遇到的小問題

在實作angularjs-placeholder module時,在IE7發現一個小問題,無法取得placeholder的值,但是在有的jQuery情況,都會幫忙處理掉了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* input default: <input placeholder="Please,enter your name!" type="text" />
*/


//use native

var attr = input.getAttribute("placeholder");

// attr == null
console.log( attr );

//use jqlite
var $elem = angular.element( input );

// attr == null
console.log( $elem.attr( "placeholder" ) );

所以如果要在IE7取得placeholder,這時候native有提供另一個api可以使用。

1
2
3
4
5
6
var node = input.getAttributeNode( "placeholder" );

var attr = node?node.nodeValue:node;

//Please,enter your name!
console.log( attr );

Titanium相同檔名會拋出錯誤

大部分的程式,只要檔名大小寫不同,就會視為不同的檔案,但是在titanium編譯的時候,則會發生錯誤,因為titanium不允許在相同資料夾裡,有相同的檔案名稱。因為之前一直是用tishadow測試,都沒遇到這個問題,最後要build在device上,就遇到了以下錯誤。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[ERROR] /home/sparrow/Works/test/build/android/bin/assets/Resources/actions/IndexAction.js: error: File is case-insensitive equivalent to: /home/sparrow/Works/ec2/test/build/android/bin/assets/Resources/actions/indexAction.js
[ERROR] Exception occured while building Android project:
[ERROR] Traceback (most recent call last):
[ERROR] File "/home/sparrow/.titanium/mobilesdk/linux/3.1.2.GA/android/builder.py", line 2621, in <module>
[ERROR] builder.build_and_run(True, avd_id, device_args=device_args, debugger_host=debugger_host, profiler_host=profiler_host)
[ERROR] File "/home/sparrow/.titanium/mobilesdk/linux/3.1.2.GA/android/builder.py", line 2400, in build_and_run
[ERROR] launched, launch_failed = self.package_and_deploy()
[ERROR] File "/home/sparrow/.titanium/mobilesdk/linux/3.1.2.GA/android/builder.py", line 1867, in package_and_deploy
[ERROR] unsigned_apk = self.create_unsigned_apk(ap_, webview_js_files)
[ERROR] File "/home/sparrow/.titanium/mobilesdk/linux/3.1.2.GA/android/builder.py", line 1679, in create_unsigned_apk
[ERROR] resources_zip = zipfile.ZipFile(resources_zip_file)
[ERROR] File "/usr/lib/python2.7/zipfile.py", line 701, in __init__
[ERROR] self.fp = open(file, modeDict[mode])
[ERROR] IOError: [Errno 2] No such file or directory: '/home/sparrow/Works/ec2/test/build/android/bin/app.ap_'
[ERROR] Build process exited with code 1
[ERROR] Project failed to build after 1m 40s 422ms

解決方法就是更換其中一個檔案的名稱,有了這次教訓…,以後盡量不使用相同檔案名稱。

Javascript prototype and this記憶體用量

在javascript中,使用function建立一個object時,用prototype來配置屬性,被建立的object會指向同一個prototype object,而使用this建立的,則會是獨立的屬性

Example:

定義TomMary二個人。

1
2
3
4
5
6
7
function Tom(){

}

function Mary(){

}

使用prototype定義John的父母,分別為TomMary

1
2
3
4
5
6
John.prototype = {
parents:{
dad:new Tom(),
mom:new Mary()
}
};

this的方式定義John的父母。

1
2
3
4
5
6
7
function John(){

this.parents = {
dad:new Tom(),
mom:new Mary()
};
}

然後用thisprototype的方式,各自建立1000000

1
2
3
4
5
var people = [];

for( var i = 0; i < 1000000 ; i++ ){
people.push( new John() );
}

結果如下:

使用prototype的方式
使用this的方式

this使用的記憶體為72.5m,而prototype的記憶體是25m,由此可知,使用prototype來建立多個object,會節省很多記憶體。


完整Prototype Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>use "prototype"</h1>
<button id="create">create children</button>
<div id="count">0</div>

<script type="text/javascript">
function Tom(){

}

function Mary(){

}

function John(){

}

John.prototype = {
parents:{
dad:new Tom(),
mom:new Mary()
}
};

var people = [],countElem = document.querySelector("#count");

document.querySelector("#create").addEventListener( "click", function(){

for( var i = 0; i < 1000000 ; i++ ){
people.push( new John() );
}

countElem.innerHTML = people.length;
});

</script>
</body>
</html>

完整This Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>use "this"</h1>
<button id="create">create children</button>
<div id="count">0</div>

<script type="text/javascript">

//define dad
function Tom(){

}

//define mom
function Mary(){

}

//define child
function John(){

this.parents = {
dad:new Tom(),
mom:new Mary()
};
}


var people = [],countElem = document.querySelector("#count");

//create children
document.querySelector("#create").addEventListener( "click", function(){

for( var i = 0; i < 1000000 ; i++ ){
people.push( new John() );
}

countElem.innerHTML = people.length;
});

</script>
</body>
</html>

Javascript Prototype的概念

javascript的prototypethis,是剛接觸javascript的人比較難理解的。在javascript裡,假設定義一個一個Bird function時,可使用同個prototype建立不同物件,也就所有經由Bird function產生的物件,都會擁有相同的protoype的屬性。

Example:

定義一隻鳥,這種鳥的名稱叫做Sparrow

1
2
3
4
5
6
7
function Bird(){
//do something
}

Bird.prototype = {
name:"Sparrow"
};

接著建立兩個變數,分別為Tom的寵物

1
2
var bird = new Bird();
var petOfTom = new Bird();

Tom把他的寵物稱為Raven,而這種的名稱,重新命名為Black Sparrow

1
2
3
petOfTom.name = "Raven";

Bird.prototype.name = "Black Sparrow";

最後你就會發現一個有趣現象,即使這種的名稱重新命名了,Tom的寵物仍然會以Tom命名的方式顯示

1
2
3
4
5
//name of bird:Black Sparrow 
console.log( "name of bird:" + bird.name );

//Tom's pet called him: Raven.
console.log( "Tom's pet called him: " + petOfTom.name + "." );

也就是說也就是說,當prototype的name改變時,其他經由Bird new出來的object name,都會跟著修改但是被new出來的object,一旦屬性被修改,不管之後prototype如何更動,則object的屬性會依照你所指定的修改


完整範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>

<script type="text/javascript">

function Bird(){

}

Bird.prototype = {
name:"Sparrow"
};

var bird = new Bird();
var petOfTom = new Bird();

console.log( "name of bird:" + bird.name );

//rename
petOfTom.name = "Raven";

//rename
Bird.prototype.name = "Black Sparrow";

console.log( "rename..." );

console.log( "name of bird:" + bird.name );

console.log( "Tom's pet called him: " + petOfTom.name + "." );

</script>

</body>
</html>

python encode

在作業系統上都有預設語言,例如windows上預設可能是big5,linux則是utf8。當python要轉換編碼的時候,可以使用encode,但是有個先決條件,必須要先把編碼轉換成作業系統的預設語言

以linux為例,要轉成big5,需先decode成utf8,在encode成big5:

1
2
3
4
5
6
# -*- coding: utf-8 -*-

u_hello = "哈囉".decode("utf8")
big5_hello = u_hello.encode("big5")

print big5_hello

接著將轉換過得字串寫入到檔案,在用gedit、word…之類的軟體,以big5編碼開啟就能看到剛剛寫入文字。

1
2
3
4
#write to file
f = open( "big5_text.txt", "w" )
f.write( big5_hello )
f.close()

另外在字串前面加個u,和decode成utf8相同:

1
2
3
4
5
6
7
8
9
10
11
>>> u"哈囉" == "哈囉".decode("utf8")
True

>>> type("哈囉")
<type 'str'>

>>> type(u"哈囉")
<type 'unicode'>

>>> type("哈囉".decode("utf8"))
<type 'unicode'>

如果是windows的作業系統,只要先將decode成big5,即可轉成其他編碼。

Running AngularJS App on IE7

IE7需要額外在body宣告宣告id和ng-app屬性:

1
<body id="ng-app" ng-app="myapp">

盡量使用class、attribute的寫法,例如:

1
2
<div class="ng-view"></div>
<div ng-view></div>

若要在IE7使用angular自訂定義的tag,而不採用上述方式,如下:

1
<ng-view></ng-view>

需要先執行以下script,可參考官方說明

1
2
3
4
5
6
7
8
9
10
11
12
<!--[if lte IE 8]>
<script>
document.createElement('ng-include');
document.createElement('ng-pluralize');
document.createElement('ng-view');

// Optionally these for CSS
document.createElement('ng:include');
document.createElement('ng:pluralize');
document.createElement('ng:view');
</script>
<![endif]-->

在IE8、IE7使用angular.fromJson,需額外include script,http://bestiejs.github.com/json3/

1
2
3
<!--[if lte IE 8]>
<script src="/static/js/libs/json3.min.js"></script>
<![endif]-->