英文原版: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配置,让我们来看下租赁信息会不会随着输入而改变:
本节完