KnockoutJS 按特定属性过滤
Posted
技术标签:
【中文标题】KnockoutJS 按特定属性过滤【英文标题】:KnockoutJS filter by specific property 【发布时间】:2019-05-30 03:59:36 【问题描述】:我将 KnockoutJS 用于在 JS 中使用 getJSON 方法的求职网站。
不幸的是,我得到了这个结构:
办公室
纽约
部门 财务 工作 示例 ... 它 物流 营销华盛顿
部门 财务 它 物流 营销洛杉矶
部门 财务 它 物流 营销我用JS中的filter
-函数过滤掉了一些尚未开放的城市办公室,效果很好。
但现在我需要过滤掉所有部门除了物流,因为我只想显示特定城市的物流工作。我希望它是动态的,因此即使有更多部门来,它也只会显示物流。
我找不到一个好的解决方案。有什么想法吗?
编辑:这是虚拟 JSON:
【问题讨论】:
您是否尝试过创建处理程序?你能用虚拟 JSON 分享你的代码吗? 我尝试了很多东西,但问题似乎是深层嵌套的 JSON 结构。如果filter
-function 没有嵌套那么深,它就可以工作。稍后我将分享我的代码。
@AmitBhoyar 现在您可以看到 JSON 结构了。
1) 请创建一个minimal reproducible example。您的代码/json 应该在问题和not an image of it 中。我们无法复制图像来创建答案。 2)输入和输出是什么?输入是部门名称和城市名称,输出是工作列表?请为您的代码创建一个最小的 sn-p 或 jsfiddle。
【参考方案1】:
由于您对工作感兴趣,我建议您制作一个Job
模型,将当前仅按结构定义的数据合并到一个方便的对象中。
为了展平您的数据,您需要执行一组reduce
操作:
const jobData=offices:[location:"ny",departments:[name:"Logistics",jobs:[title:"driver for x",title:"driver for y"],name:"Finance",jobs:[title:"CFO"]],location:"la",departments:[name:"Logistics",jobs:[title:"driver for z"],name:"IT",jobs:[title:"tech support manager"]]]
const Job = (title, department, officeLocation) => (
title,
department,
officeLocation
);
const JobList = ( offices ) => (
jobs: offices.reduce(
(allJobs, location, departments ) => departments.reduce(
(allJobs, name, jobs ) => jobs.reduce(
(allJobs, title ) => allJobs.concat(
Job(title, name, location)
),
allJobs
),
allJobs
),
[]
)
)
console.log(JobList(jobData))
现在我们已经整理好了数据格式,我们可以开始编写淘汰赛代码了。
我创建了一个table
,它呈现一个计算出的作业列表。在计算中,我们过滤 2 个属性:所需的办公室和所需的部门。
过滤器本身是“扁平的”,因为Job
对象包含我们需要的所有数据。例如,物流过滤器可以这样应用:
const logisticsJobs = ko.pureComputed(
jobList().filter(job => job.department === "logistics")
);
这是一个例子。使用表头中的<select>
元素来应用过滤器。
function JobFinder()
const jobData = ko.observable( offices: [] );
const jobList = ko.pureComputed(
() => JobList(jobData())
);
// Lists of properties we can filter on
this.offices = ko.pureComputed(
() => uniques(jobList().map(job => job.officeLocation))
);
this.departments = ko.pureComputed(
() => uniques(jobList().map(job => job.department))
);
// Filter values
this.requiredOffice = ko.observable(null);
this.requiredDepartment = ko.observable(null);
// Actual filter logic
const officeFilter = ko.pureComputed(
() => this.requiredOffice()
? job => job.officeLocation === this.requiredOffice()
: () => true
);
const departmentFilter = ko.pureComputed(
() => this.requiredDepartment()
? job => job.department === this.requiredDepartment()
: () => true
);
const allFilters = ko.pureComputed(
() => [ officeFilter(), departmentFilter() ]
)
const filterFn = ko.pureComputed(
() => job => allFilters().every(f => f(job))
)
// The resulting list
this.filteredJobs = ko.pureComputed(
() => jobList().filter(filterFn())
);
// To load the data (can be async in real app)
this.loadJobData = function()
jobData(getJobData());
;
// Initialize app
const app = new JobFinder();
ko.applyBindings(app);
app.loadJobData();
// utils
function uniques(xs) return Array.from(new Set(xs));
// Code writen in the previous snippet:
function getJobData()
return offices:[location:"ny",departments:[name:"Logistics",jobs:[title:"driver for x",title:"driver for y"],name:"Finance",jobs:[title:"CFO"]],location:"la",departments:[name:"Logistics",jobs:[title:"driver for z"],name:"IT",jobs:[title:"tech support manager"]]];
;
function Job(title, department, officeLocation)
return
title,
department,
officeLocation
;
function JobList( offices )
return offices.reduce(
(allJobs, location, departments ) => departments.reduce(
(allJobs, name, jobs ) => jobs.reduce(
(allJobs, title ) => allJobs.concat(
Job(title, name, location)
),
allJobs
),
allJobs
),
[]
)
;
th
text-align: left;
width: 30%
;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table>
<thead>
<tr>
<th>Job Title</th>
<th>Location</th>
<th>Department</th>
</tr>
<tr>
<th></th>
<th>
<select data-bind="
options: offices,
value: requiredOffice,
optionsCaption: 'Show all locations'">
</select>
</th>
<th>
<select data-bind="
options: departments,
value: requiredDepartment,
optionsCaption: 'Show all departments'">
</select>
</th>
</tr>
</thead>
<tbody data-bind="foreach: filteredJobs">
<tr>
<td data-bind="text: title"></td>
<td data-bind="text: officeLocation"></td>
<td data-bind="text: department"></td>
</tr>
</tbody>
</table>
【讨论】:
非常感谢您提供如此详细的回答。我会试试看。以上是关于KnockoutJS 按特定属性过滤的主要内容,如果未能解决你的问题,请参考以下文章