星期四, 2月 09, 2017

Angular $rootScope and $scope Event System

Angular官方對的 $rootScope 的定義如下
Every application has a single root scope. All other scopes are descendant scopes of the root scope. Scopes provide separation between the model and the view, via a mechanism for watching the model for changes. They also provide event emission/broadcast and subscription facility.
 一個ng-app只會有一個 $rootScope,所有的 $scope 都是 $rootScope 的child scope。文件特別把angular的emission/broadcast機制放在定義,這也代表事件處理是 $rootScope 很重要的操作。

$scope.$emit up, $scope.$broadcast down


// firing an event upwards
$scope.$emit('myCustomEvent', 'Data to send');

// firing an event downwards
$scope.$broadcast('myCustomEvent', {
  someProp: 'Sending you an Object!' // send whatever you want
});

// listen for the event in the relevant $scope
$scope.$on('myCustomEvent', function (event, data) {
  console.log(data); // 'Data to send'
});


簡單說明這三個行為

  • $emit 往上(parent)觸發事件
  • $broadcast 往下(child)觸發事件
  • $on 當收到事件所執行的行為


但是$scope的互動並非都是parent-child關係,有可能是Sibling之間要觸發。這時候就會要先$emit parentScope在$broadcast,並不是很方便的寫法。


$scope.$parent.$broadcast('myevent', 'Some data');


$rootScope.($emit/$broadcast)


上面的這種sibling的事件觸發,則可以使用$rootScope代為處理,如下方案例。
簡單說明 $rootScope 的 $emit 跟 $broadcast 的差別。
  • $rootScope.$emit 因為$rootScope沒有父層,所以直接觸發 $rootScope 註冊的事件。
  • $rootScope.$broadcast 往下廣播事件。

<div ng-controller="ParentCtrl as parent" class="ng-scope">
  // ParentCtrl
  <div ng-controller="SiblingOneCtrl as sib1" class="ng-scope">
    // SiblingOneCtrl
  </div>
  <div ng-controller="SiblingTwoCtrl as sib2" class="ng-scope">
    // SiblingTwoCtrl
    <div ng-controller="ChildCtrl as child" class="ng-scope">
      // ChildCtrl
    </div>
  </div>
</div>



app.controller('SiblingOneCtrl',
  function SiblingOneCtrl ($rootScope) {

  $rootScope.$on('rootScope:emit', function (event, data) {
    console.log(data); // 'Emit!'
  });
  
  $scope.$on('rootScope:broadcast', function (event, data) {
    console.log(data); // 'Broadcast!'
  });
  
  $rootScope.$on('rootScope:broadcast', function (event, data) {
    console.log(data); // 'Broadcast!'
  });

});

app.controller('ChildCtrl',
  function ChildCtrl ($rootScope) {

  $rootScope.$emit('rootScope:emit', 'Emit!'); // $rootScope.$on
  $rootScope.$broadcast('rootScope:broadcast', 'Broadcast'); // $rootScope.$on && $scope.$on

});


Ref.1 AngularJS Offical Document: $rootScope
Ref.2 Understanding Angular’s $scope and $rootScope event system $emit, $broadcast and $on

星期三, 10月 05, 2016

React Component shouldComponentUpdate 實作


最近朋友遇到一個有趣的React問題,可能頁面上有個值,一秒鐘會有幾萬筆資料進來,但是如果要一直更新畫面,效果不好。

這邊我推薦使用shouldComponentUpdate 來阻擋這種一秒鐘幾十萬資料變動的畫面呈現議題。

範例程式碼如下
http://jsbin.com/lilubaj

1. ParentComponent每1ms變動一次數值給ChildComponent(this.state.count)。
2. ChildComponent會在畫面上呈現(this.props.count)。
3. shouldComponentUpdate 有個timer設置每1秒才會允許畫面更新一次。
4. componentWillReceiveProps 原本的資料還是每1ms都會更新(資料流是正確的)。



星期二, 7月 12, 2016

Redux middleware 筆記

使用redux middleware完成非同步呼叫

我們團隊在開始使用action->dispatch->reducer其實進入蠻快的
但是當進入到非同步的時候就卡關了
因為要在action creator要處理非同步,如果不使用middleware
我們可能會在action creator

export function addTodo(text) {
  setTimeout(function () { 
return { type: ADD_TODO, text }
  },3000)
}
但是reducer會跟你說錯,因為回來的東西並不是action而是一個function,reducer無法處理,這時候就需要middleware處理了。


我們大概可以把 middleware當作redux流程中的一部分。

action->dispatcher->customized async middleware-> reducer 產生新的state。

============async call sample===========

var Promise = require('bluebird');
var Superagent = require('superagent');

function asyncMiddleware(){
 return function store(store){ 
   return function next(next){ //next middleware
    return function actionHandle(action){ 
    if (typeof action.ASYNC_CALL !== 'undefined') {
     return next(action); 
     //如果action沒有關鍵字ASYNC_CALL,則直接走下一個middleware
    }
    var type = action.type;
    
    return new Promise(function promiseHandle(resolve, reject){
     //這邊我們使用bluebird的Promise來達成promise
     
     function responseCallback(responseError, response){
      //some code error handle or resolve promise

      next({
       type: type,
       response: response
      });
      
      resolve(response);
      
     }
     
     //do ajax call
     //這邊我們是使用superagent 來get/put/post/delete
     Superagent.get(target).query(params).set(header).end(responseCallback);
    });
   }
  }
 }
}

=========action creator=================
而我們的action creator就很簡單了
例如下面這個是非同步呼叫載入個人資料



export const LOADED_PROFILE = 'LOADED_PROFILE';
export function loadProfile(params) {
 return {
  'ASYNC_CALL': { //有此關鍵字 middleware會走 ajax call
   type: LOADED_PROFILE,
   method: 'get',
   target: '/profile/:pid',
   params: params
  }
 };
};

=========component/container===========

import { loadProfile } from 'actions/profile';

class Profile  extends Component {
 componentDidMount() {
  var params = {};//get/post的參數 
  this.props.loadProfile(params).then(function(result) {
   //do something
  });
 }
}
var mapDispatchToProps = { loadProfile };
export default connect(mapStateToProps, mapDispatchToProps)(Profile);


=========小結=====================

透過這種方式,團隊成員在使用redux流程都會很一致的
action->(middlewares)->reducer->store

不用知道middlewares的細節就可以完成開發
(不過當然我都有解釋給他們聽原理)



=========附註======================

我們是從redux-thunk的source code理解實作方法的
https://github.com/gaearon/redux-thunk/blob/master/src/index.js
只有短短10多行程式碼

redux middleware的說明官方文件跟有人從頭跑過一次redux middleware的中文說明
http://redux.js.org/docs/advanced/Middleware.html
http://huli.logdown.com/posts/294284-javascript-redux-middleware-details-tutorial



星期日, 7月 10, 2016

React-Redux 筆記

react-redux其實概念我整理如下

  • 有個中央控管的rootStore
  • 元件把自己需要的rootStore map回去變成自己的props
  • 元件可以發出action去變動rootStore 進而更新自己的畫面


=================Store層========================
rootStore管理整個React App的資料(我們先稱他為root)
ex:

{ root : 
 profile:{...profileData},
 friend: {...friendData},
 privacy: {...privacy}
}
=================Action定義層========================
action會定義我們的操作
ex:

const ADD_PROFILE_DATA = 'ADD_PROFILE_DATA';
addProfileData(data) {
 {
 type: ADD_PROFILE_DATA,// for reducer使用
 data:data //這個action會變動的資訊
 }
}

=================Reducer定義層========================
reducer負責處理 action來的狀態變化
所以跟rootStore類似,我們會拆幾個reducer來處理


rootReducer= combineReducers({
 profileReducer,
 friendReducer,
 privacyReducer
});

const profileReducer = function (state, action ) {

  switch(action.type) //action所定義的type
    case 'ADD_PROFILE_DATA'

    state.profile = action.data
    return state; //這兩個的意義 (state, action) => new state
  
    default: 
    return state;//沒定義的action不變動state
}

=================Component/Container(view)定義層=========
React-redux的元件跟react元件最大的不同就是有引入react-redux的connect()方法。



import { connect } from 'react-redux';
import {addProfileData} from 'action/profile';
class Profile extends Component { 
//react lifecycle method, render methor
}
mapStateToProps (state) {
  profile: state.profile 
  //我的Profile只需要profile的資料
  //就map rootStore的 profile變成自己的props
  //如果今天有其他的action變動到rootStore profile的資料
  //Profile也會跟著更新狀態
}

export default connect( 
  mapStateToProps, { addProfileData } ,{/*mergeProps*/},{/*option*/})( Profile );


要熟悉react-redux 對他提供的connect一定要熟悉
第一個連接的是這個component的mapStateToPros 這個function
第二個是這個component會發出的action,官方是稱他為 mapDispatchToProps
做了上述兩個動作,這個react component就在redux資料流當中了

this.props.profile就有相對應的資料
this.props.addProfileData 也可以dispatch透過reducer,更新rootStore的資料。

第三個參數 mergeProps 第四個為option
後兩個比較少用,避免混淆觀念,我這篇先跳過,有興趣可以參閱官方API
https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-apdispatchtoprops-mergeprops-options


=================後序========================
以上是最基本的redux在react的應用流程,
之後還有要跟大家說的,如果redux會使用到非同步呼叫或是其他功能需求(ex logger),
我們是使用redux middleware來完成。

星期二, 11月 05, 2013

[公告] 網誌搬家

各位好,最近把網誌搬到 - http://kvzhuang.logdown.com/ (其實已經搬了一段時間了)。

是個很不錯的部落格,歡迎大家多多瀏覽推薦阿。

之後會把網域也一併搬過去。

星期二, 8月 06, 2013

[COSCUP] 2013 COSCUP 參與心得

  這次參加COSCUP是我第一次參加。雖然我本身專注前端技術,但是其實本次的議程我並沒有只關注前端的議題,反而到處去看 Open Data,零時政府的議題。我才發現一個感覺是,我們並不是一群關上門來寫程式的人。我們十分關注時事,關切社會。


g0v.tw 高嘉良臥病仍不忘撰寫程式碼。(圖取自 inside.com.tw)

  這次的議題到處可以看到和時事相關的議題,拆政府,國防布。CLKao也有一句讓我印象十分深刻的話"政府應該停止使用網頁點擊率當作績效的KPI,而是資料的使用率做為績效的KPI"。

  文人使用文字改變社會,程式設計師使用程式碼改變社會。 Code 不再是只有社會的高級分子,立法委員能夠撰寫,你我都能夠參與改變社會,是我這次參加活動最大的感動。

零時政府網站
如何參與零時政府 g0v hackpad

  還有我在師大資工研究所老師,中央資工副教授鄭永斌老師也上台說 Lighten talk,表達他對希望資工所甄試有所變革的期望所下的行動。都是令人十分值得推廣的。



星期四, 7月 25, 2013

[人文] 驚喜合唱 101 Flash Mob Chorus in Taipei 101, Taiwan

  最近看到朋友分享了一個驚喜合唱 101 Flash Mob Chorus in Taipei 101, Taiwan。就很想要幫忙宣傳一下,真的會令人感動的台灣情!

  大家也可以幫忙轉貼出去啊! 台灣人就是那麼熱情有感情的民族。


星期二, 6月 25, 2013

[css] units of css

  這次來介紹 css的度量衡,尺寸介紹。尺寸共有三種類型,一種是絕對數值,如 inch, cm, mm, pt(point), pc(pica), 這種和日常生活相關的尺寸。另外一種是比例上的計算,如 em,ex或 %,最後一種則是特別的單位  px 。

  首先先介紹絕對數值,基於現實生活數值,所以呈現的情況在各種裝置下將會一致,也因此不建議使用在螢幕上,原因是呈現出來螢幕的大小是很多變的,若使用固定尺寸輸出將會造成呈現錯誤。

  絕對數值的轉換公式為 1in = 2.54cm = 25.4mm = 72pt = 6pc。

  接下來來討論比例上的計算,以em當例子,若我們設定字形尺寸為 2in, 1em 就相當於 2in。 em 相關於 font-size大小,所以字體大小也影響到 em的所呈現的大小。我們也常看到 "text-ident: 1.5em" 或是 "margin: 1em"這種用法,都是配合字體大小設定所呈現的格式。下方我做了個 em實例,有機會可以去實驗看看。

Check out this Pen!

  最後介紹 px 這個特別的單位,他和上述兩個不一樣的地方是,他是基於電腦螢幕所發展出來的規格,定義在最小,但是是可以看見的一個單位下所創造出來的螢幕單位。而 px 這名字則是來自於 screen pixels。


  下面這張圖是 W3C 各種單位推薦的的使用方法。也可以參考看看。


參考資料: W3C - EM, PX, PT, CM, IN…

星期三, 6月 19, 2013

[RGBA] difference between index and alpha transparency

  今天稍微介紹一下 Index以及 Alpha 透明度的差異。首先我們先介紹 Index透明度, Index透明度我們以 GIF檔案舉例,一個 GIF檔案會分做兩部分: Color Table 以及圖像的資料。 Color Table 是一個用於此圖像的顏色列表,如果是 8-bit的 GIF圖檔,就會有2^8= 256種顏色在此 Color Table。每一個顏色都被分配一個順序的數字,如下圖表示。

  GIF圖檔對應到 Color Table的數值,而呈現 Color Table紀錄的顏色。如下例,其顏色索引是 008,而相對應的呈現的顏色就是 #d8d3de。


  在 Index透明度,每個在 Color Table的顏色都可以被設定是否要被設定為是否呈現為透明色,若指定為呈現為透明色,則輸出之後就會是透明色,如下圖。
  

Alpha Transparent
  那在討論 Alpha 透明,在 Alpha透明度,每個顏色在圖像當中都有一個 alpha的數值紀錄他的透明程度,所以他們呈現的透明程度是一種可以漸變的情況。我們可以從下面兩張使用不同透明色匯出的圖形知道差異。

GIF 索引色透明
Alpha透明

  我試著用工程師的角度解釋兩者差異,也很希望設計師朋友能以不同角度解釋補述,若有錯誤也歡迎更正。


星期二, 6月 18, 2013

[html] media object

  在 twitter bootstrap裡面有一種元件類別叫做 media object,其樣式就是一個圖像在左邊,而相對應的文字敘述在右邊。這種樣式真的現在到處在哪邊都用的到,當然若使用一些框架,單純直接遵照規定使用撰寫即可,但是如果沒有使用框架,為了之後好維護我把我自己訂的一個樣板分享出來給大家。


   Source Code: https://github.com/kvzhuang/public_html/blob/master/2013/media-object.html
  相信有更好的做法,也很歡迎各位給予意見指教。