您好我正在尝试过滤在SearchBar的按键上通过HTTP请求获取的可观察数据数据。
我设法让 SearchBar 属性更改工作,但我似乎无法弄清楚我在过滤逻辑中做错了什么。
理想情况下,我想在SearchBar
中输入搜索字词时更新列表。我在Telerik网站上搜索了API,我找不到任何可以找到的例子。
XML
<Page loaded="pageLoaded">
<ActivityIndicator busy="{{ isLoading }}" />
<ActionBar title="People">
</ActionBar>
<GridLayout>
<StackLayout>
<SearchBar id="searchBar" hint="Search for someone"></SearchBar>
<ListView items="{{ peopleList }}" itemTap="showDetail">
<ListView.itemTemplate>
<StackLayout>
<Label text="{{ fullName }}" horiztonalAlignment="left" verticalAlignment="center"></Label>
<Label text="{{ company }}" class="info"></Label>
</StackLayout>
</ListView.itemTemplate>
</ListView>
</StackLayout>
</GridLayout>
</Page>
JS
var frames = require("ui/frame");
var Observable = require("data/observable").Observable;
var PeopleListViewModel = require("../../shared/people-viewModel");
var activityIndicatorModule = require("ui/activity-indicator");
var page;
var userkey;
var peopleList = new PeopleListViewModel([]);
var pageData = new Observable({ peopleList: peopleList });
exports.pageLoaded = function(args) {
page = args.object;
page.bindingContext = pageData;
userkey = userkey || page.navigationContext.userkey;
peopleList.load(userkey); // fetch data from the backend
var searchBar = page.getViewById("searchBar");
searchBar.on("propertyChange", function (args) {
var searchText = args.object.text;
if (searchText === "") {
// NOT SURE WHAT TO DO HERE.
} else {
peopleList.filter(function (element, index, array) {
// DOESN"T WORK PROPERLY
console.log("element: ", JSON.stringify(element));
return element.fullName == searchText;
});
console.log("Text types: ", searchText);
}
});
};
exports.showDetail = function(args) {
var person = peopleList.getItem(args.index);
var navigateEntry = {
moduleName: "views/people/people-detail",
context: { person: person },
animated: false
};
frames.topmost().navigate(navigateEntry);
};
PeopleListViewModel.js
var config = require("./config");
var fetchModule = require("fetch");
var ObservableArray = require("data/observable-array").ObservableArray;
function PeopleListViewModel(people) {
var viewModel = new ObservableArray(people);
viewModel.load = function (userKey) {
return fetchModule.fetch(config.baseUrl + "/api/people/all/" + userKey)
.then(function (response) {
return response.json();
})
.then(function (data) {
data.forEach(function (person) {
viewModel.push(person);
});
}, function (error) {
console.log("Error: ", error);
});
};
viewModel.empty = function () {
while (viewModel.length) {
viewModel.pop();
}
};
return viewModel;
}
function handleErrors(response) {
if (!response.ok) {
console.log("Error occurred");
}
}
module.exports = PeopleListViewModel;
更新了人员列表
var frames = require("ui/frame");
var Observable = require("data/observable").Observable;
var ObservableArray = require("data/observable-array").ObservableArray;
var PeopleListViewModel = require("../../shared/people-viewModel");
var activityIndicatorModule = require("ui/activity-indicator");
var page;
var userkey;
var peopleList = new PeopleListViewModel([]);
var pageData = new Observable({ peopleList: peopleList });
var resultList = new ObservableArray([]);
exports.pageLoaded = function(args) {
page = args.object;
page.bindingContext = pageData;
userkey = userkey || page.navigationContext.userkey;
peopleList.load(userkey);
var searchBar = page.getViewById("searchBar");
searchBar.on("propertyChange", function (args) {
var searchText = args.object.text;
if (searchText === "") {
} else {
while (resultList.length > 0) {
resultList.pop();
}
peopleList.forEach(function (element) {
if (element.fullName === searchText) {
resultList.push(element);
}
});
}
});
};
答案 0 :(得分:5)
我有同样的问题。如果您想在搜索栏中更改每个字符后过滤数据,可以尝试我的解决方案。
<强>解释强> 我的playerList是你的peopleList。这是来自视图模型的数据。 resultList是一个数据将被推送的数组。
var observableArrayModule = require("data/observable-array").ObservableArray;
var playerList = new PlayerListViewModel([]);
var resultList = new observableArrayModule([]);
var pageData = new observableModule.Observable({
resultList: resultList,
player: ""
});
内部expors.loaded()
page = args.object;
searchBar = page.getViewById("search-bar");
page.bindingContext = pageData;
加载初始数据 - 在expors.loaded()
中当用户第一次导航到屏幕时,我们正在加载初始数据。我们也将相同的数据推送到resultList,因为我们在xml中使用{{resultList}}。您可以在填充列表时添加loadingIndicator。
playerList
.load()
.then(function() {
setTimeout(function() {
playerList.forEach(function (element) {
pageData.resultList.push(element);
});
}, 1000);
})
.catch(function(error) {
dialogsModule.alert({
message: "An error occurred while loading players.",
okButtonText: "OK"
});
});
清除自动对焦 - 在expors.loaded()
中这是为了防止键盘在初始屏幕导航时打开。
if (searchBar.ios) {
searchBar.ios.endEditing(true);
} else if (searchBar.android) {
searchBar.android.clearFocus();
}
在角色发生变化时搜索数据 - 在expors.loaded()
中我正在调用过滤器功能。 Lodash _.debounce函数用于延迟通过resultList数组的循环。没有它,应用程序将在每次输入字母时循环。现在我们正在等待用户停止输入以开始循环。
searchBar.on('propertyChange', _.debounce(searchList, 500));
搜索列表功能
这是实际的循环。您可以根据需要更改element.name。
function searchList(args) {
var searchText = args.object.text;
while(resultList.length > 0) {
resultList.pop();
}
playerList.forEach(function (element) {
if (element.name.toLowerCase().indexOf(searchText) >= 0) {
resultList.push(element);
}
});
}
如果清除了搜索栏,则隐藏键盘 - 在exports.loaded()
中最后,如果用户清除搜索栏,我们想要隐藏键盘。
searchBar.on(searchBarModule.SearchBar.clearEvent, function (args) {
setTimeout(function() {
searchBar.dismissSoftInput();
}, 10);
});
PS
你可能已经解决了你的问题,但这可能在将来帮助其他人。
答案 1 :(得分:1)
好的,所以你的问题是一个Javascript问题而不是NativeScript问题。为了解决这个问题,可以将可观察数组视为普通数组。
在您的JS中,您需要创建一个新的PeopleListViewModel
,然后通过pageData
对象附加到bindingContext。到现在为止还挺好。然后,您在load
上调用PeopleListViewModel
方法(它会返回一个您未真正做过任何事情的承诺,但针对此特定问题并不重要)
然而,当文本被输入时,你并没有真正做任何事情。这是你的代码:
peopleList.filter(function (element, index, array) {
// DOESN"T WORK PROPERLY
console.log("element: ", JSON.stringify(element));
return element.fullName == searchText;
});
peopleList
是PeopleListViewModel
的一个实例,它返回ObservableArray
。 ObservableArray确实有一个名为filter
的方法(它就像常规数组的过滤器一样。查看filter
的{{3}}和NativeScript documentation。
您需要了解的是,filter
会返回包含已过滤结果的新数组。执行peopleList.filter()
会将新数组发送到空白区域。你想要var yourNewFilteredArray = peopleList.filter()
。但是你并不想重新定义绑定到绑定上下文的数组,你想要修改它的内容。
以下是您如何做到这一点的示例:
/*
* Attach a new obsersable array to the binding context.
* you can prepopulate it with the data from the
* PeopleListViewModel if you want to
*/
var resultList = new ObservableArray([]);
var pageData = new Observable({ resultList: resultList });
/*
* Then on search/filter you want to modify this new
* array. Here I first remove every item in it and then
* push matching items to it.
*/
searchBar.on("propertyChange", function (args) {
var searchText = args.object.text;
// ...
while(resultList.length > 0) {
resultList.pop();
}
peopleList.forEach(function (element) {
if (element.fullName === searchText) {
resultList.push(element);
}
});
});