Ember旅程系列(九) -- 构建一个比较复杂的组件

英文原版:https://guides.emberjs.com/v2.13.0/tutorial/autocomplete-component/

正如用户在搜索租赁信息,正常情况下他们会指定他们的搜索条件,比如按照所在城市来搜索。然而我们之前建立租赁列表仅仅罗列了所有租赁条目。我们现在要创建一个过滤器组件,可以让用户在输入框中输入他们想要的搜索条件,并得到他们想要的结果。

开始行动,我们创建一个新组件。我们称之为list-filter,让它来实现搜索过滤功能:

ember g component list-filter

我们之前创建rental-listing组件的时候,”generate component”命令帮我们创建了:

  • 助手模板(app/templates/components/list-filter.hbs)。
  • javascript源文件(app/components/list-filter.js)。
  • 组件的集成测试文件(tests/integration/components/list-filter-test.js)。

我们将会在app/templates/rentals.hbs模板文件中,引入刚刚创建的
list-filter组件。

app/templates/rentals.hbs

<div class="jumbo">
  <div class="right tomster"></div>
  <h2>Welcome!</h2>
  <p>
    We hope you find exactly what you're looking for in a place to stay.
  </p>
  {{#link-to 'about' class="button"}}
    About Us
  {{/link-to}}
</div>

{{#list-filter
   filter=(action 'filterByCity')
   as |rentals|}}
  <ul class="results">
    {{#each rentals as |rentalUnit|}}
      <li>{{rental-listing rental=rentalUnit}}</li>
    {{/each}}
  </ul>
{{/list-filter}}

需要注意的是我们将之前rentals的相关代码包含在list-filter助手的开始和结束标记之间。它将会使得list-filter助手标记之间的内容(rentals的相关代码)被渲染到list-filter组件模板中{{yield}}助手的位置,这种形式我们称之为块组件

在这种情况下,被我们过滤出的数据会保存在这个名叫rentals的变量中(list-filter开始标记),进而继续被{{each}}助手所使用。

我们希望组件可以提供一个input输入框用来输入条件,并且可以将过滤后的数据展示在块它的中。所以我们可以如下的简单定义list-filter组件的模板:

app/templates/components/list-filter.hbs

{{input value=value
        key-up=(action 'handleFilterEntry')
        class="light"
        placeholder="Filter By City"}}
{{yield results}}

这个模板包含了一个{{input}}助手,它可以被渲染成一个文本控件。它的value属性的值将会与list-filter组件中的value属性的值同步变化。

说白了,其实就是{{input}}的value属性和组件的value属性之间存在双向绑定了。input的value值变化会使得组件中value属性的值也变化;反之亦然。变化的结果也会反映在页面上和组件代码中。

key-up属性其实就是onkeyup事件,指定该事件的回调函数为handleFilterEntry。

如下是list-filter组件的javascript代码:

app/components/list-filter.js

import Ember from 'ember';

export default Ember.Component.extend({
  classNames: ['list-filter'],
  value: '',

  init() {
    this._super(...arguments);
    this.get('filter')('').then((results) => this.set('results', results));
  },

  actions: {
    handleFilterEntry() {
      let filterInputValue = this.get('value');
      let filterAction = this.get('filter');
      filterAction(filterInputValue).then((filterResults) => this.set('results', filterResults));
    }
  }
});

我们在init()钩子函数中调用了一个被传入空字符串参数的filter方法(这里用来做初始化,传入空就是等价于没有进行搜索)。
handleFilterEntry方法基于{{input}}助手的value值来调用filter()方法。

请注意,在filter()后接着调用了then()方法。这表明filter()会返回一个promise对象(关于Promise想请自行百度,这里不再赘述)。

为了让filter()能正常工作,并为我们按照所在城市来过滤数据。我们将会创建一个rentals控制器。控制器包含了在当前路由的模板中可使用的方法和属性。我们接下来创建一个名叫rentals的控制器。Ember会自觉地明白这个控制器将会为与它同名的路由服务。

用命令生成控制器:

ember g controller rentals

参照如下内容定义你的控制器:

app/controllers/rentals.js

import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    filterByCity(param) {
      if (param !== '') {
        return this.get('store').query('rental', { city: param });
      } else {
        return this.get('store').findAll('rental');
      }
    }
  }
});

当用户在list-filter组件的input中输入内容的时候,控制器中的filterByCity()方法就会被调用。并且该方法会将input的value值和store中的数据做对比。并且将符合条件的数据返回到调用处。

为了让这个方法顺利工作,我们需要将Mirage的config.js文件中的内容改变一下,以使得能够顺利响应我们的查询请求。相对于仅仅返回租赁数据,Mirage的HTTP GET助手能做到根据发送来的关键字,按照city属性来返回响应的租赁信息。

mirage/config.js

export default function() {
  this.namespace = '/api';

  let rentals = [{
      type: 'rentals',
      id: 'grand-old-mansion',
      attributes: {
        title: 'Grand Old Mansion',
        owner: 'Veruca Salt',
        city: 'San Francisco',
        "property-type": 'Estate',
        bedrooms: 15,
        image: 'https://upload.wikimedia.org/wikipedia/commons/c/cb/Crane_estate_(5).jpg',
        description: "This grand old mansion sits on over 100 acres of rolling hills and dense redwood forests."
      }
    }, {
      type: 'rentals',
      id: 'urban-living',
      attributes: {
        title: 'Urban Living',
        owner: 'Mike Teavee',
        city: 'Seattle',
        "property-type": 'Condo',
        bedrooms: 1,
        image: 'https://upload.wikimedia.org/wikipedia/commons/0/0e/Alfonso_13_Highrise_Tegucigalpa.jpg',
        description: "A commuters dream. This rental is within walking distance of 2 bus stops and the Metro."
      }
    }, {
      type: 'rentals',
      id: 'downtown-charm',
      attributes: {
        title: 'Downtown Charm',
        owner: 'Violet Beauregarde',
        city: 'Portland',
        "property-type": 'Apartment',
        bedrooms: 3,
        image: 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Wheeldon_Apartment_Building_-_Portland_Oregon.jpg',
        description: "Convenience is at your doorstep with this charming downtown rental. Great restaurants and active night life are within a few feet."
      }
    }];

  this.get('/rentals', function(db, request) {
    if(request.queryParams.city !== undefined) {
      let filteredRentals = rentals.filter(function(i) {
        return i.attributes.city.toLowerCase().indexOf(request.queryParams.city.toLowerCase()) !== -1;
      });
      return { data: filteredRentals };
    } else {
      return { data: rentals };
    }
  });
}

更新完Mirage配置,让我们来看下租赁信息会不会随着输入而改变:
这里写图片描述

本节完

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值