從服務器獲取數據,引入組件

博文原址:http://blog.ddlisting.com/2016/04/21/yin-ru-zu-jian/html

接着前面四篇:git

  1. 環境搭建以及使用Ember.js建立第一個靜態頁面
  2. 引入計算屬性、action、動態內容
  3. 模型,保存數據到數據庫
  4. 發佈項目,加入CRUD功能

清理模板,使用組件重構

2.0版本以後組件會愈來愈重要。有關組件的介紹請看Ember.js 入門指南之二十八組件定義。組件的建立一樣可使用Ember CLI命令建立。以下命令建立了2個組件,建立的同時會自動建立2個文件;一個是組件類(app/components/xxx.js)。一個是組件對應的模板(app/templates/components/xxx.hbs)。github

ember g component library-item
ember g component library-item-form

修改模板library-item數據庫

下面在組件模板library-item.hbs中增長以下代碼:ubuntu

<!-- app/templates/components/library-item.hbs -->
<div class="panel panel-default library-item">
    <div class="panel-heading">
        <h3 class="panel-title">{{item.name}}</h3>
    </div>
    <div class="panel-body">
        <p>Address: {{item.address}}</p>
        <p>Phone: {{item.phone}}</p>
    </div>
    <div class="panel-footer text-right">
      {{yield}}
    </div>
</div>

若是注意看能夠發現上述代碼與app/templates/libraries/index.hbs文件的代碼很是類似。這是item替代了model。至於item是怎麼來的請看Ember.js 入門指南之二十九屬性傳遞,這篇博文介紹了組件的屬性傳遞,item是從調用組件的模板傳遞過來的。上述代碼中還有一個重要的東西是{{yield}},這個表達式與{{outlet}}相似。一樣也是一個佔位符。組件渲染以後會被傳進來的html代碼替換。好比下面的調用代碼:vim

{{#library-item item=model}}
  Closed
{{/library-item}}

組件渲染以後,上述的Closed會替換到{{yield}}這裏,最終獲得的html代碼以下:api

<div class="panel-footer text-right">
      Closed
</div>

有關組件渲染的內容請看Ember.js 入門指南之三十包裹內容app

修改模板library-item-formless

<!-- app/templates/components/library-item-form.hbs -->
<div class="form-horizontal">
    <div class="form-group has-feedback {{if item.isValid 'has-success'}}">
        <label class="col-sm-2 control-label">Name*</label>
        <div class="col-sm-10">
          {{input type="text" value=item.name class="form-control" placeholder="The name of the Library"}}
          {{#if item.isValid}}<span class="glyphicon glyphicon-ok form-control-feedback"></span>{{/if}}
        </div>
    </div>
    <div class="form-group">
        <label class="col-sm-2 control-label">Address</label>
        <div class="col-sm-10">
          {{input type="text" value=item.address class="form-control" placeholder="The address of the Library"}}
        </div>
    </div>
    <div class="form-group">
        <label class="col-sm-2 control-label">Phone</label>
        <div class="col-sm-10">
          {{input type="text" value=item.phone class="form-control" placeholder="The phone number of the Library"}}
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-default" {{action 'buttonClicked' item}} disabled="{{unless item.isValid 'disabled'}}">{{buttonLabel}}</button>
        </div>
    </div>
</div>

注意觀察上述代碼與libraries/new.hbslibraries/edit.hbs幾乎是同樣的。有點不同的是把校驗移到model中。好比校驗name屬性不爲空。 注意:頂部導入的代碼。ide

import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import Ember from 'ember';

export default Model.extend({
  name: attr('string'),
  address: attr('string'),
  phone: attr('string'),

  isValid: Ember.computed.notEmpty('name')
});

再修改app/templates/libraries/index.hbs引入組件。

<h2>List</h2>
<div class="row">
  {{#each model as |library|}}
    <div class="col-md-4">
      {{#library-item item=library}}
        {{#link-to 'libraries.edit' library.id class='btn btn-success btn-xs'}}Edit{{/link-to}}
        <button class="btn btn-danger btn-xs" {{action 'deleteLibrary' library}}>Delete</button>
      {{/library-item}}
    </div>
  {{/each}}
</div>

在迭代中使用組件,經過屬性名item傳遞迭代出來的對象library到組件中。其中link-tobutton這兩句代碼會替換到組件library-item{{yield}}上。 等待項目重啓完成,能夠看到界面與以前的沒有任何變化。頁面是沒有變化,可是後臺的處理還須要完善。

修改app/templates/libraries/new.hbs

<!-- app/templates/libraries/new.hbs -->
<h2>Add a new local Library</h2>

<div class="row">

  <div class="col-md-6">
      {{library-item-form item=model buttonLabel='Add to library list' action='saveLibrary'}}
  </div>

  <div class="col-md-4">
      {{#library-item item=model}}
          <br/>
      {{/library-item}}
  </div>

</div>

修改app/templates/libraries/edit.hbs

<h2>Edit Library</h2>

<div class="row">
    <div class="col-md-6">
      {{library-item-form item=model buttonLabel='Save changes' action='saveLibrary'}}
    </div>

    <div class="col-md-4">
      {{#library-item item=model}}
        <br/>
      {{/library-item}}
    </div>

</div>

在組件類library-item-form.js增長對action的處理。

import Ember from 'ember';

export default Ember.Component.extend({
  buttonLabel: 'Save',

  actions: {

    buttonClicked(param) {
      this.sendAction('action', param);
    }

  }
});

合併edit.hbsnew.hbsform.hbs

原來的文件edit.hbsnew.hbs幾乎是同樣的,可使用組件重構。

<!-- /app/templates/libraries/form.hbs -->
<h2>{{title}}</h2>

<div class="row">
    <div class="col-md-6">
      {{library-item-form item=model buttonLabel=buttonLabel action='saveLibrary'}}
    </div>

    <div class="col-md-4">
      {{#library-item item=model}}
        <br/>
      {{/library-item}}
    </div>

</div>

爲了實現代碼複用,首先把不一樣的部分定義成屬性:titlebuttonLabel。默認狀況下路由會渲染到同名的模板上,若是你想修改這個默認行爲可使用renderTemplate()方法。

使用方法renderTemplate()setupController()

API介紹

默認狀況下路由會渲染到同名的模板上,咱們使用方法renderTemplate()執行渲染的模板。好比下面的代碼使用這個方法執行路由new渲染到模板libraries/form.hbs

// app/routes/libraries/new.js
import Ember from 'ember';

export default Ember.Route.extend({

  model: function () {
    return this.store.createRecord('library');
  },

  setupController: function (controller, model) {
    this._super(controller, model);

    controller.set('title', 'Create a new library');
    controller.set('buttonLabel', 'Create');
  },

  renderTemplate() {
    this.render('libraries/form');
  },

  actions: {

    saveLibrary(newLibrary) {
      newLibrary.save().then(() => this.transitionTo('libraries'));
    },

    willTransition() {
      let model = this.controller.get('model');

      if (model.get('isNew')) {
        model.destroyRecord();
      }
    }
  }
});

注意方法setupController()設置組件模板中的屬性titlebuttonLabel的值。一樣的在修改路由edit.js

// app/routes/libraries/edit.js
import Ember from 'ember';

export default Ember.Route.extend({

  model(params) {
    return this.store.findRecord('library', params.library_id);
  },

  setupController(controller, model) {
    this._super(controller, model);

    controller.set('title', 'Edit library');
    controller.set('buttonLabel', 'Save changes');
  },

  renderTemplate() {
    this.render('libraries/form');
  },

  actions: {

    saveLibrary(newLibrary) {
      newLibrary.save().then(() => this.transitionTo('libraries'));
    },

    willTransition(transition) {
      let model = this.controller.get('model');

      if (model.get('hasDirtyAttributes')) {
        let confirmation = confirm("Your changes haven't saved yet. Would you like to leave this form?");

        if (confirmation) {
          model.rollbackAttributes();
        } else {
          transition.abort();
        }
      }
    }
  }
});

使用組件重構以後能夠刪除app/templates/libraries/new.hbsapp/templates/libraries/edit.hbs,這兩個文件不須要了。效果截圖以下:

頁面重構截圖

使用組件nav-link-to重構<li><a></a></li>

知道組件如何使用以後咱們繼續重構項目代碼,重構導航模板navbar.hbs的連接代碼。使用Ember CLI命令建立組件。

ember g component nav-link-to

此次使用擴展的方式擴展一個組件類,擴展Ember內置的組件類LinkComponent,使用方法extend()擴展一個類。而後使用屬性tagName指定渲染以後的標籤。更多有關組件屬性的介紹請看Ember.js 入門指南之三十一自定義包裹組件的HTML標籤,固然你也能夠參考網址的教程實現本文的需求。

// app/components/nav-link-to.js
import Ember from 'ember';

export default Ember.LinkComponent.extend({
  tagName: 'li'
});

注意:記得修改Ember.Component.extendEmber.LinkComponent.extend。組件模板很簡單。

<!-- app/templates/components/nav-link-to.hbs -->
<a href="">{{yield}}</a>

最後在修改導航模板navbar.hbs爲以下內容:

<!-- app/templates/navbar.hbs -->
<nav class="navbar navbar-inverse">
  <div class="container-fluid">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#main-navbar">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      {{#link-to 'index' class="navbar-brand"}}Library App{{/link-to}}
    </div>

    <div class="collapse navbar-collapse" id="main-navbar">
      <ul class="nav navbar-nav">
            {{#nav-link-to 'index'}}Home{{/nav-link-to}}
            {{#nav-link-to 'libraries'}}Libraries{{/nav-link-to}}
            {{#nav-link-to 'about'}}About{{/nav-link-to}}
            {{#nav-link-to 'contact'}}Contact{{/nav-link-to}}
      </ul>

      <ul class="nav navbar-nav navbar-right">
          <li class="dropdown">
              <a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Admin<span class="caret"></span></a>
              <ul class="dropdown-menu">
                  {{#nav-link-to 'admin.invitation'}}Invitations{{/nav-link-to}}
                  {{#nav-link-to 'admin.contact'}}Contacts{{/nav-link-to}}
              </ul>
          </li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>

等待項目重啓完成,能夠看到界面與以前的沒有任何變化,能夠任意點擊導航欄菜單且不會出錯。效果截圖以下:

最終結果截圖

家庭做業

本篇的家庭做業就是好好理解組件!參考下面的文章認真學習、理解組件。

  1. Ember.js 入門指南之二十八組件定義
  2. Ember.js 入門指南之二十九屬性傳遞
  3. Ember.js 入門指南之三十包裹內容
  4. Ember.js 入門指南之三十一自定義包裹組件的HTML標籤
  5. Ember.js 入門指南之三十二處理事件
  6. Ember.js 入門指南之三十三action觸發變化

<br> 爲了照顧懶人我把完整的代碼放在[GitHub](https://github.com/ubuntuvim/library-app)上,若有須要請參考參考。博文通過屢次修改,博文上的代碼與github代碼可能有出入,不過影響不大!若是你以爲博文對你有點用,請在github項目上給我點個`star`吧。您的確定對我來講是最大的動力!!

相關文章
相關標籤/搜索