code-prettify

顯示具有 AngularJS 標籤的文章。 顯示所有文章
顯示具有 AngularJS 標籤的文章。 顯示所有文章

2016年9月18日 星期日

Bootstrap SB Admin 2 整合 AngularJS 遇到 metisMenu 問題

使用 Bootstrap SB Admin 2 (Live Preview) 樣版 ,
整合 AngularJS 遇到了幾個關於 metisMenu  (Live Demo) 的問題,

第一個問題是如果 menu 在 ng-include 裡面的話,
並不會正常運作,而是處於完全展開的情況。
原因是原本在 sb-admin-2.js 的程式碼:

$(function() {
    $('#side-menu').metisMenu();
});

在第一次載入頁面時已執行完畢,
當 angular app 載入 ng-include 之後,並沒有做任何的動作。
解決辦法就是在 ng-include 加入 onload 函式,
在 controller 加入下列程式碼後解決:

$scope.loaded = function() {
    $('#side-menu').metisMenu();
}

完整的 Plunker 範例



第二個問題是 metisMenu 的 active 功能沒有正常運作,
原因一樣是因為原本的設計是頁面載入完成後執行程式碼:

var url = window.location;
var element = $('ul.nav a').filter(function() {
    return this.href == url;
}).addClass('active').parent().parent().addClass('in').parent();
 if (element.is('li')) {
    element.addClass('active');
}

然而使用 Angular 實作 Single Page Application 之後,
切換頁面並不會重新載入 js,所以沒有觸發這個動作。
解決辦法是當頁面改變後執行這個動作,如下列程式碼:

.run(['$rootScope', function ($rootScope) {
    $rootScope.$on('$viewContentLoaded', function (event) {
        $('ul.nav a').removeClass('active');

        var url = window.location;
        var element = $('ul.nav a').filter(function () {
            return this.href == url || url.href.indexOf(this.href) == 0;
        }).addClass('active').parent().parent().addClass('in').parent();

        if (element.is('li')) {
            element.addClass('active');
        }
    });
}]);



jquery metisMenu not working inside ng-include
http://stackoverflow.com/questions/26335696/jquery-metismenu-not-working-inside-ng-include

Finished Loading of ng-include in angular js
http://stackoverflow.com/questions/27576643/finished-loading-of-ng-include-in-angular-js

2016年7月19日 星期二

如何使用 Closure Compiler 最小化 JavaScript 產生 Source Maps 後進行偵錯

本文介紹以一個 AngularJS App 當範例,如何使用 Closure Compiler 最小化 (minimizes) 後產生的 Source Map 透過 Chrome 來進行偵錯 (Debug)。

Closure Compiler 是 Google 開發的 JavaScript 最小化編譯器,
關於細節可以參考 Google Closure Compiler 編譯器:產生最佳化(最小化)JavaScript 程式碼

本文使用的範例是 Kuroneko Idle Game (雖然不能算是一個遊戲)
所有的程式碼在 GitHub
https://github.com/allyusd/kuroneko
範例網站
http://allyusd.github.io/kuroneko

首先看一下完整建置指令
java -jar compiler-latest\compiler.jar --js_output_file myapp.min.js --create_source_map myapp.min.js.map --output_wrapper "%%output%%//# sourceMappingURL=myapp.min.js.map" js/**.js

這一段指令,將 js 目錄下含子目錄的所有 js 檔案,都合併成 myapp.min.js,並且在最後加上 sourceMappingURL 相關文字,同時產生 myapp.min.js.map 這個 Source Map 檔案。

參數介紹
js_output_file 表示最小化後輸出的 js 檔案名稱
create_source_map 表示同時要產生 Source Map,並指定檔案名稱
output_wrapper 可以進行加工,這個例子是加上 #sourceMappingURL 關鍵字

先介紹一下最小化,在開發 AngularJS (或任何 JavaScript 應用) 時,大部份的情況像是下圖的結構。


透過 Closure Compiler 可以合併成單一檔案,減少 Http request 次數,減少空白或換行字元,用短變數的替換…等等的好處。但是衍生了一個問題,就是不方便偵錯,這是用 Chrome 看到最小化後的結果(部份)。



人是貪心的,有沒有辦法魚與熊掌兼得呢?

實際上是有的,就是利用 Source Map,只要加上 create_source_map 參數就能產生,但是要如何使用呢?

我們在最小化的檔案 myapp.min.js 加上 sourceMappingURL 告訴瀏覽器 Source Map 的位置,接著用 Chrome 查看會出現下圖。



眼尖的話會發現除了 myapp.min.js 外出現很多斜體字檔案,其實就是合併前的 js 檔。開心的別太早,點開檔案發現裡面是空白的,因為並沒有把原始檔案上傳,如果有上傳的話,這時候已經可以看到原本的 JavaScript 檔案內容。

因為不想上傳多餘的東西,所以我們要偵錯的話必須讓 Chrome 知道原本的檔案在哪裡,首先在空白處點擊 Add folder to workspace


指定本地檔案路徑後,Chrome 上方會出現授權請求及警語。


按下允許後下方會出現本地工作目錄。

接著剩下最後一個動作了,在上面斜體字檔案按下右鍵,選擇 Map to file system resource...


最後選擇對應的本地檔案就完成了,結果如下圖


這些原始檔可不是只能看看而已,可以下中斷點的偵錯的喔!




資料來源
Introduction to JavaScript Source Maps
http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/

Map Preprocessed Code to Source Code
https://developers.google.com/web/tools/chrome-devtools/debug/readability/source-maps

Secrets of the Browser Developer Tools
http://devtoolsecrets.com/secret/debugging-use-javascript-source-maps.html

Set Up Persistence with DevTools Workspaces
https://developers.google.com/web/tools/setup/setup-workflow

2014年8月7日 星期四

AngularJS - angular-ui-router 實現 Nested Views 及 Multiple Views

在試著使用 AngularJS 實作 Kuroneko Idle Game 時遇到了問題,
ngRoute 不支持 巢狀 View 及多重 View 的實現。
幸好在 Google 上找到了救兵 ui-router,以下是兩種寫法的差別。

ngRoute 寫法:
app.js config:
index.html:
ui-router 寫法:
app.js config:
index.html:
main.html (新增):
這麼一來就完成了巢狀 View 的實作。

Reference
GitHub - angular-ui/ui-router

2014年3月13日 星期四

AngularJS SPA 實作 - ngRoute - 使用 angular-seed 為範例

SPA 就是 Single Page Application,這次試著用 AngularJS 來實作 SPA,主要使用的是 Route 功能,這次的範例來源是 angular-seed,但是只保留所需要的部份。

需要的檔案分別如下

    index.html
    css/app.css
    js/app.js
    js/controllers.js
    partials/partial1.html
    partials/partial2.html

接著我們一個一個來看

index.html

<!doctype html>
<html lang="en" ng-app="myApp">
<head>
  <meta charset="utf-8">
  <title>My AngularJS App</title>
  <link rel="stylesheet" href="css/app.css"/>
</head>
<body>
  <ul class="menu">
    <li><a href="#/view1">view1</a></li>
    <li><a href="#/view2">view2</a></li>
  </ul>

  <div ng-view></div>

  <div>Angular seed app: v<span app-version></span></div>

  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular-route.js"></script>
  <script src="js/app.js"></script>
  <script src="js/controllers.js"></script>
</body>
</html>

第 11~12 行的連結位址是 #/view1,特別注意開頭是使用 # 宣告路徑,這會讓 AngularJS 的 Rount 去解析該路徑 view1 應該如何對應,連結按下後會到 index.html#/view1。
第 15 行宣告 ng-view,這個 div 就是各個 view 將會顯示的區域。
19~22 行一樣是載入所需要的 js 檔,這邊有刪除幾個原本 angular-seed 的 js 連結,有需要使用其它功能的時候再加進去。

app.js

'use strict';

// Declare app level module which depends on filters, and services
angular.module('myApp', [
  'ngRoute',
  'myApp.controllers'
]).
config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/view1', {templateUrl: 'partials/partial1.html', controller: 'MyCtrl1'});
  $routeProvider.when('/view2', {templateUrl: 'partials/partial2.html', controller: 'MyCtrl2'});
  $routeProvider.otherwise({redirectTo: '/view1'});
}]);

第 1 行 'use strict' 請參考 [JavaScript]use strict(嚴格模式)-strict mode 介紹 這篇文章。
第 9~11 行就是 Rount 的主要用法,/view1 就是網址上 index.html#/view1 所對應到的路徑,這裡設定將會使用 partial1.html 為 template,MyCtrl1 為 controller,view2 以此類推。
第 12 行則表示,如果上述的路徑都不符合的時候,將會導向 view1 路徑。

其它的部份,像是 controllers.js 和 partial1.html, partial2.html 就不解釋了,有需要的話可以參考之前的文章:
AngularJS - 官方範例 - 01 - The Basics
AngularJS - 官方範例 - 02 - Add Some Control

所有的 Source Code 都可以從 DEMO 網頁取得:
DEMO 網頁

參考資料
angular-seed
https://github.com/angular/angular-seed

延伸閱讀
Single Page Apps with AngularJS Routing and Templating
http://scotch.io/tutorials/javascript/single-page-apps-with-angularjs-routing-and-templating

[JavaScript]use strict(嚴格模式)-strict mode 介紹
http://www.dotblogs.com.tw/blackie1019/archive/2013/08/30/115977.aspx

2014年2月26日 星期三

AngularJS - 官方範例 - 02 - Add Some Control

上次介紹了第一個範例 The Basics,示範了 AngularJS 的 Data Binding 能力。
這次介紹官網第二個範例,Add Some Control,所展示的是 AngularJS Controller的用法,
主題是常見的 ToDo List。

一樣先看一下結果:
新增一個待辦事項:debug
按下 archive,將已完成的事項刪除
將 build an angular app 標註為已完成

看完了成果,接著來看程式碼:
html

<!doctype html>
<html ng-app>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
 <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
 <script src="js/todo.js"></script>
 <link rel="stylesheet" href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" />
 <link rel="stylesheet" href="http://angularjs.org/css/docs.css">
    <link rel="stylesheet" href="css/todo.css">
  </head>
  <body>
  <div class="tabs-spacer"></div>
 <div class="span4 well">
    <h2>Todo</h2>
  <div ng-controller="TodoCtrl">
    <span>{{remaining()}} of {{todos.length}} remaining</span>
    [ <a href="" ng-click="archive()">archive</a> ]
    <ul class="unstyled">
   <li ng-repeat="todo in todos">
     <input type="checkbox" ng-model="todo.done">
     <span class="done-{{todo.done}}">{{todo.text}}</span>
   </li>
    </ul>
    <form ng-submit="addTodo()">
   <input type="text" ng-model="todoText"  size="30"
       placeholder="add new todo here">
   <input class="btn-primary" type="submit" value="add">
    </form>
  </div>
 </div>
  </body>
</html>

除了第 8 行新加了 todo.js 之外,其它在第一個範例都介紹過了,todo.js 等等會說明
17 行宣告了 ng-controller,宣告了 Controller 的範圍及此 Ctrl 的名稱為 TodoCtrl
18 行宣告一個 {{remaining()}},會顯示 remaining 這個函式的回傳值。 {{todos.length}} 則會顯示 todos 這個陣列有多少個項目
19 行 ng-click="archive()",所以 archive 這個連結被 click 時,會呼叫 archive 函式。
21 行 ng-repeat="todo in todos",ng-repeat 就像 for each,會依據 todos 這個 Array 有多少個項目而重覆多少次 (這個例子來說,會重覆 <li> 到 </li>之間的內容)。同時,宣告 todos 陣列取出來項目叫 todo,供 li 裡面使用。
22 行 ng-model="todo.done",把這個 input 的值跟 todo.done 綁定了
23 行 {{todo.done}} 用來決定這個 span 的 class 名稱是 "done-true" 或 "done-false",目的是搭配 css 來作顯示風格上的變化,以這個例子來說,就是灰色字體及刪除線。後面的{{todo.text}} 會顯示 todo.text 的內容。
26 行 ng-submit="addTodo()",當這個 form submit 時,會呼叫 addTodo 函式。
27 行同樣是 ng-model 的資料綁定
28 行就是 submit 按鈕

todo.js

function TodoCtrl($scope) {
  $scope.todos = [
    {text:'learn angular', done:true},
    {text:'build an angular app', done:false}];
 
  $scope.addTodo = function() {
    $scope.todos.push({text:$scope.todoText, done:false});
    $scope.todoText = '';
  };
 
  $scope.remaining = function() {
    var count = 0;
    angular.forEach($scope.todos, function(todo) {
      count += todo.done ? 0 : 1;
    });
    return count;
  };
 
  $scope.archive = function() {
    var oldTodos = $scope.todos;
    $scope.todos = [];
    angular.forEach(oldTodos, function(todo) {
      if (!todo.done) $scope.todos.push(todo);
    });
  };
}

第 2 行宣告一個函式為 TodoCtrl,也就是 html 的 ng-controller 所寫的名稱。當 AngularJS 產生一個 Controller 時,會將此函式當作建構函式,並且注入一個 scope 物件。
3~5 行初始化 todos,有兩個項目
7~10 行宣告 addTodo 是一個函式,會將 todoText 當成新項目的內容,並新增到 todos 裡,同時會清空 todoText。
12~18 行宣告 remaining 函式,計算 todos 裡面有多少個項目的 done 屬性是 ture。
20~26 行宣告 archive 函式,將 todos 裡項目的 done 是 false 的保留。(也就是清除 done 是 true 的項目)

DEMO 網頁

參考來源:
angularjs.org
http://angularjs.org/

2014年2月20日 星期四

AngularJS - 官方範例 - 01 - The Basics

AngularJS 官方網站 第一個範例,The Basics 主要示範雙向資料綁定 (Two-way data binding)。
首先看一下成果:


當我們在文字框輸入文字時,會更新變數,
同時,因為變數改變了,連帶畫面也更新了。
完整程式碼如下:


<html ng-app="">
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
 <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
 <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet"></link>
 <link href="http://angularjs.org/css/docs.css" rel="stylesheet"></link>
  </head>
  <body>
 <div class="tabs-spacer">
</div>
<div class="span4 well">
  <div>
    <label>Name:</label>
    <input ng-model="yourName" placeholder="Enter a name here" type="text" />
    <hr />
    <h1>
Hello {{yourName}}!</h1>
</div>
</div>
</body>
</html>
第 2 行 ng-app 宣告整個 html 都是 AngularJS 的應用範圍
5~9 行加入所需要的檔案,除了 angular.min.js 之外,其它都是為了美觀而加上去的,對於此範例的功能來說是不必要的!
11~14 行也是為了美觀,仿 AngularJS 官方網站的,所以前面才會用到 angularjs.org 的 css。
16 行 ng-model="yourName",就是將此 input 欄位跟 yourName 這個變數綁定,只要此 input 發生變化,Model 裡面的變數也會跟著變化。
19 行 {{yourName}} 則是顯示 yourName 變數,當 Model 的變數變化,顯示也跟著變化。

整個執行結果就是, 當 input 的值發生改變時, {{yourName}} 也跟著改變。

直接看 DEMO,體驗一下
DEMO 網頁

參考來源:
angularjs.org
http://angularjs.org/