2014年12月16日 星期二

Run Asp.Net vNext on Mac

前言:
.NET已經OpenSource了!但我相信這個消息早就不是新聞了,國外也有很多人分享了如何在很潮的Mac上寫.NET應用。只是英文的教學很多但是中文的卻很少,趁著機會趕緊分享一下自己在Mac上面安裝.NET開發相關環境的心得。

內文:
由於ASP.NET已經正式OpenSource了,原始碼都放在GitHub上而且官方教學也是放那裡,因此我們就從官方的教學來一步步完成吧。
官方連結:https://github.com/aspnet/home#getting-started

1)安裝KVM
首先,要去安裝KVM(K Version Manager)這是一個幫助管理KRE(K Runtime Environment)的工具,我們可以在同一時間安裝不同版本的KRE並且指定目前預設的KRE是哪一套。KVM我們可以用HomeBrew安裝,因此安裝方式超簡單。
下以下command把這個GitHub Repos加入HomeBrew的追蹤裡。

brew tap aspnet/k

接著run以下的command安裝KVM

brew install kvm

接下來依照指示在bash_profile中加入source kvm.sh
vim .bash_profile

2)安裝KRE
裝好KVM後執行upgrade
kvm upgrade
這個指令可以幫助我們下載KRE並且設為預設,現在最基本的環境這樣就架好了!
當然,工欲善其事,必先利其器 接下來我們就是要把開發環境的好用工具都裝上才行

3)下載Sublime Text 3
http://www.sublimetext.com/3

4)安裝Kulture
在Sublime Text中使用package Controller安裝package

5)安裝OmniSharp
在Sublime Text中使用package controller安裝package
這個套件強烈建議安裝,這是for intellisence用的,裝上去之後就會有智慧提醒,不用記長死人不償命的function name那些東西了~ XD

6)下載.NET官方提供的Demo project
切到你的工作目錄下並下指令
git clone https://github.com/shirhatti/Home.git
檔案其實不大,所以很快就會抓完了XD

下載完畢後,它的結構大概是Home資料夾底下有samples資料夾,samples裡面有有三個資料夾,我們先切到ConsoleApp這個資料夾底下並下command
kpm restore
這個指令會幫我們把專案相依的NuGet package給裝起來,由於這個console app所以我們直接下command就可以看到執行結果
k run
這個指令一執行後Terminal就會顯示出那個讓人熟悉又感動的Hello World!

console app是相對簡單的,比較不一樣的是web app,官方提供的samples有兩個web,我們就拿MVC來做例子吧~
一樣我們切到HelloMvc目錄下並把package裝上
這個web專案我們就換用sublime Text示範
用sublime Text開啟專案目錄,並且下 shift+command+p
輸入"k"找到Run k commands,選擇k kestrel這個指令
預設會run在port 5004上(若是用kesterl run的話),設定可以去看project.json的內容裡面都有寫。
選擇k kestrel後會跑一個console去run web server,這個時候去瀏覽器瀏覽http://localhost:5004就可以看到新版的Mvc的預設樣式囉~!

其實.NET寫了幾年了,從沒想過微軟也會走向如此開放的地步,終於可以不用在Linux或Mac上用virtualbox安裝windows來寫.NET應用了XD
還滿感動的 XD

2014年12月2日 星期二

Take a peek at EmberJS - Phase3

前言:
接續上次的文章,我們這次要把要一步一步把功能給實做完成~!
第一階段
第二階段

內文:
延續上次的文章,我們已經完成Todo應用的CUD(新增、修改、刪除),接下來我們要做的便是可以讓使用者filter已經完成的Todo,哪些又是尚未完成的Todo。因此這邊我們需要把我們的Template分成數個子Template並利用框架的Route來做到讓這些事情在同一頁完成。
首先我們先把列表頁的內容抽出來變成一個新的Template
<!-- data-template-name內的值就相當於是一個路由,index是讓這個Template顯示的路由值,裡面的資料來源從哪裡來則從route去設定 -->
<script type="text/x-handlebars" data-template-name="MyTodos/index">
    <ul id="todo-list">
        {{#each itemController="MyTodoList"}}
        <li {{bind-attr class="isCompleted:completed isEditing:editing" }}>
            {{#if isEditing}}
            {{input class="edit" value=title focus-out="acceptChanges" insert-newline="acceptChanges"}}
            {{else}}
            {{input type="checkbox" checked=isItemCompleted class="toggle"}}
            <label {{action "editTodo" on="doubleClick" }}>{{title}}</label><button {{action "removeTodo" }} class="destroy"></button>
            {{/if}}
        </li>
        {{/each}}
    </ul>
</script>
而原本的Template就變成如下:
<script type="text/x-handlebars" data-template-name="MyTodos">
    <section id="todoapp">
        <header id="header">
            <h1>todos</h1>
            {{input type="text" id="new-todo" placeholder="What needs to be done?" value=myTitle1 action="createTodo"}}
        </header>

        <section id="main">
            {{outlet}}
            <input type="checkbox" id="toggle-all">
        </section>
</script>
<!--忽略很多-->
Handlebars helper "{{outlet}}" 是用來幫助我們宣告一個區域,當我們改變route時可以render出指定route的畫面,而第一個child route就會是填滿這個區塊的route。
改完View之後我們要新增一個route.js檔案,在裡面撰寫route相關的邏輯。
Todos.Router.map(function () {
    
    // 當Uri為'/'時去render名稱為「MyTodos」的Template
    this.resource('MyTodos', { path: '/' }, function () {
        //額外的child routes
    });
});

Todos.MyTodosRoute = Ember.Route.extend({
    // 表明這個route要顯示的model是那個
    model: function () {
        return this.store.find('MyTodo');
    }
});

// EmberJS的controller預設的route名稱就是Index,因此若直接存取預設的controller那麼根據框架就會去render Index的內容
Todos.MyTodosIndexRoute = Ember.Route.extend({
    // 這邊表示index的model就是MyTodos
    model: function () {
        return this.modelFor('MyTodos');
    }
});

現在重新刷一次頁面應該就可以看到我們的清單顯示於頁面中。不過我們還要這個Todo應用可以切換以做完、未做完的顯示。首先還是來調整一下頁面。
<script type="text/x-handlebars" data-template-name="MyTodos">
<!--忽略很多-->
        <footer id="footer">
            <span id="todo-count">
                <strong>{{remaining}}</strong> {{inflection}} left
            </span>
            <ul id="filters">
                <li>
                    {{#link-to "MyTodos.index" activeClass="selected"}}All{{/link-to}}
                </li>
                <li>
                    {{#link-to "MyTodos.active" activeClass="selected"}}Active{{/link-to}}<--會打到active這個route>
                </li>
                <li>
                    {{#link-to "MyTodos.completed" activeClass="selected"}}Completed{{/link-to}}
                </li>
            </ul>
<!--忽略很多-->
</script>
接著調整一下route.js的內容,讓route知道這兩個route分別要呈現什麼東西。
Todos.Router.map(function () {
    
    // 當Uri為'/'時去render名稱為「MyTodos」的Template
    this.resource('MyTodos', { path: '/' }, function () {
        // 這些route會在MyTodo這個Route之下
        this.route('active');// MyTodos.active
        this.route('completed');// MyTodos.completed
    });
});

<!--忽略...-->

Todos.MyTodosActiveRoute = Ember.Route.extend({
    model: function () {
        return this.store.filter('MyTodo', function (todo) {
            return !todo.get('isCompleted');
        });
    },
    renderTemplate: function (controller) {
        //這裡重複使用了既存的Template來render
        this.render('MyTodos/index', { controller: controller });
    }
});

Todos.MyTodosCompletedRoute = Ember.Route.extend({
    model: function () {
        return this.store.filter('MyTodo', function (todo) {
            return todo.get('isCompleted');
        });
    },
    renderTemplate: function (controller) {
        this.render('MyTodos/index', { controller: controller });
    }
});
現在重新刷一下畫面,應該已經可以切換完成、未完成的項目了。接下來我們新增一個可以清除所有已經完成的項目的功能。還是一樣,首先修改頁面
<footer id="footer">
<!--忽略...-->
            {{#if hasCompleted}}
            <button id="clear-completed">
                {{action "clearCompleted"}}
                Clear completed ({{completed}})
            </button>
            {{/if}}
</footer>
接下來我們要在Controller中新增以下功能
Todos.MyTodosController = Ember.ArrayController.extend({

// 忽略好大一段...

    // 清空已經完成的項目
    clearCompleted: function () {
        var completed = this.filterBy('isCompleted', true);
        // emberjs的array api提供的方法
        completed.invoke('deleteRecord');
        completed.invoke('save');
    },

    hasCompleted: function () {
        return this.get('completed') > 0;
    }.property('completed'),

    completed: function () {
        return this.filterBy('isCompleted', true).get('length');
    }.property('@each.isCompleted')
)};
重刷一下畫面後,功能就實做完成了~!但,既然有清除全部已經做完當然也會有全部已做完的功能才是
因此我們再來改一下畫面
<!--忽略...-->
        <section id="main">
            {{outlet}}
            {{input type="checkbox" id="toggle-all" checked=allAreDone}}
        </section>
<!--忽略...-->
//忽略很多...

allAreDone: function (key, value) {
        if (value === undefined) {
            return !!this.get('length') && this.isEvery('isCompleted', true);
        } else {
            this.setEach('isCompleted', value);
            this.invoke('save');
            return value;
        }
    }.property('@each.isCompleted')
好~改好之後存好檔,重新刷一下頁面這樣我們的全選功能就算完成了~!

以上這些小功能都完成後,一個簡單的Todo應用的基本能力就實做完成了,剩下的就是資料來源的問題,這就流到下次吧 = =汗