I work with semantic ui and when I do a search on a website the result is empty but when I look at my console I see the json result
this is my js code
$('.ui.search').search({
apiSettings: {
url: "https://api.github.com/search/repositories?q={query}"
},
fields: {
results: 'items',
title: 'name',
url: 'html_url',
description: 'description'
}
});
and my html code
<div class="ui right aligned category search item">
<div class="ui transparent icon input">
<input class="prompt" placeholder="Rechercher" type="text">
<i class="search link icon"></i>
</div>
<div class="results"></div>
</div>
screenshot results in my html page
and i have try the exemple for semantic-ui page
$('.ui.search')
.search({
type : 'category',
minCharacters : 3,
apiSettings : {
onResponse: function(githubResponse) {
var
response = {
results : {}
}
;
// translate GitHub API response to work with search
$.each(githubResponse.items, function(index, item) {
var
language = item.language || 'Unknown',
maxResults = 8
;
if(index >= maxResults) {
return false;
}
// create new language category
if(response.results[language] === undefined) {
response.results[language] = {
name : language,
results : []
};
}
// add result to category
response.results[language].results.push({
title : item.name,
description : item.description,
url : item.html_url
});
});
return response;
},
url: '//api.github.com/search/repositories?q={query}'
}
})
and this is not work
have the same problem as you
debugger and get this:
debug screenshot
it seems will get 'results' field from response, so if your response without 'results' field you need set 'results' in onResponse callback:
apiSettings : {
onResponse (response) {
return {
results: response.myresults
}
}
}
and if you didn't set the templates, it will use the standard template, standard template use 'title' field to show, you need do some transform like this:
response.myresults.forEach((item) => {
item.title = item.name;
})
hope this can help you
Related
Background: I have a kendo multiselect that gets populated with emails based on the values of a kendo dropdown. I also need to use the multiselect to 'search' for additional emails through our employee api. Then as i search and select new values to be added to the 'selected values' portion of the multiselect i want to be able to go back and see the initial populated values without the searched values.
Disclaimer: I can get all of this to work except the searched values get 'added' to the datasource which I dont want. Think of a temporary datasource when searching. So when i go to look through the initial populated values, the returned search vales are appended to the datasource values. Again, I do not want this.
CODE:
<div class="row display-row">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12">
<h4>Location Group:</h4>
#(Html.Kendo().DropDownList()
.Name("weatherLocGroupNameDropDown")
.HtmlAttributes(new { style = "width:100%" })
.OptionLabel("Select location group...")
.DataTextField("LocationGroupName")
.DataValueField("LocationGroupId")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("getLocationGroupNames", "Base");
});
})
)
</div>
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12">
<h4>Location:</h4>
#(Html.Kendo().DropDownList()
.Name("weatherLocNameDropDown")
.HtmlAttributes(new { style = "width:100%" })
.OptionLabel("Select location...")
.DataTextField("LocationName")
.DataValueField("LocationId")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("getLocationNamesFilteredByLocationGroup", "Base")
.Data("filterLocation");
})
.ServerFiltering(true);
})
.Enable(false)
.AutoBind(false)
.Events(ev => ev.Change("populateLocGrpEmails"))
.CascadeFrom("weatherLocGroupNameDropDown")
)
</div>
<div class="row display-row">
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12">
#(Html.Kendo().MultiSelect()
.Name("recipientMultilist")
.Placeholder("Recipient(s)")
.AutoBind(false)
.Enable(false)
.HtmlAttributes(new { style = "width:100%" })
.DataTextField("EmailName")
.DataValueField("EmailId")
.Events(ev => ev.Filtering("searchEmails"))
)
</div>
</div>
function searchEmails() {
var searchText = $("#recipientMultilist").data('kendoMultiSelect').input.val();
searchText = searchText.trim();
if (searchText.length >= 3 && searchText != undefined && searchText != "") {
$.ajax(
{
url: "#Url.Action("getRecipientEmails", "Base")",
data: { searchTerm: searchText },
type: "GET",
dataType: "json",
async: false,
success: function (searchEmail) {
if (searchEmail.length > 0) {
for (var i = 0; i < searchEmail.length; i++) {
$('#recipientMultilist').data("kendoMultiSelect").dataSource.add({
EmailName: searchEmail[i].EmailName,
EmailId: searchEmail[i].EmailId
});
}
}
}, error: function (searchEmailErr) { console.log('searchEmailErr: ', searchEmailErr); }
})
}
}
function getLocationGroupEmails() {
return {
LocationGroupId: $("#weatherLocGroupNameDropDown").data("kendoDropDownList").value()
}
}
function filterLocation() {
return {
LocationGroupId: $("#weatherLocGroupNameDropDown").data("kendoDropDownList").value()
};
}
function populateLocGrpEmails() {
$("#recipientMultilist").data("kendoMultiSelect").enable();
tempMultiListStorage = [];
var locationText = $("#weatherLocNameDropDown").data('kendoDropDownList').text();
var locationGroupId = $("#weatherLocGroupNameDropDown").data('kendoDropDownList').value()
//get all emails associated with the location group and inserts into the recipientMultilist
$.ajax(
{
url: "#Url.Action("getEmailFilteredByLocationGroup", "Base")",
data: { LocationName: locationText, LocationGroupId: locationGroupId },
type: "GET",
dataType: "json",
async: false,
success: function (filteredEmail) {
if (filteredEmail.length > 0) {
for (var i = 0; i < filteredEmail.length; i++) {
$('#recipientMultilist').data("kendoMultiSelect").dataSource.add({
EmailName: filteredEmail[i].EmailName,
EmailId: filteredEmail[i].EmailId
});
tempMultiListStorage.push({
EmailName: filteredEmail[i].EmailName,
EmailId: filteredEmail[i].EmailId })
}
}
}, error: function (filteredEmailErr) { console.log('filteredEmailErr: ', filteredEmailErr); }
})
var multiselect = tempMultiListStorage
//"selects" the record that matches the location
var dropdownlist = $("#recipientMultilist").getKendoMultiSelect();
dropdownlist.value(locationText)
dropdownlist.trigger("change");
}
I do know that this code in searchEmails
$('#recipientMultilist').data("kendoMultiSelect").dataSource.add({
EmailName: searchEmail[i].EmailName,
EmailId: searchEmail[i].EmailId
});
is adding the values to the multiselect but thats there so i can at least test a few other things. Again, i am looking to 'see' the searched values, select the search values but not make them part of the 'datasource' by adding them.
I hope this was clear haha.
Can you give this a try and see if it works:
$("#multiselect").kendoMultiSelect({
select: function(e) {
e.preventDefault();
}
});
I have finish autocomplete with a jquery library which is
using jquery-ui-1.12.1.min.js
. I have modified it to make to get the search with username and full name. it will show as below image
when I select the value it will paste the whole text into an input box.
here is my question how do it modify it to show as the image but when I select the value it will only paste the username into input box?
how i only want nonstop00000 paste it into input box when i select the 1st value
here is my javascript
$(document).ready(function () {
$("#id").autocomplete({
source: function(request,response) {
$.ajax({
url: '#Url.Content("~/UserManagement/AutoCompleteUser")/',
type: "POST",
dataType: "json",
data: { term: request.term },
success: function (data) {
response($.map(data, function (item) {
return [{ label: item.Username + " | " + item.FullName, value: item.id }];
}))
}
})
},
messages: {
noResults: "", results: ""
}
});
})
here is my search controller
if (!String.IsNullOrEmpty(searchString))
{
user = user.Where(s => s.Username.Trim().Contains(searchString.Trim())
|| s.FullName.Trim().Contains(searchString.Trim()));
}
here is my autocomplete controller
public JsonResult AutoCompleteUser(string term)
{
var result = (from r in db.UserTables
where ((r.Status == "Active") && (r.Username.ToLower().Contains(term.ToLower()) || (r.FullName.ToLower().Contains(term.ToLower()))))
select new { Username = r.Username, FullName = r.FullName }).Distinct();
return Json(result);
}
here is my view
<div class="col-lg-9 col-md-9 col-sm-9 col-xs-12 search-panel">
#using (Html.BeginForm("Index", "UserManagement", FormMethod.Get))
{
<div class="input-group form-group ui-widget">
#Html.TextBox("id", ViewBag.CurrentFilter as string, new { #class = "form-control autocomplete", #placeholder = "Search for..." })
<span class="input-group-btn">
<input type="submit" value="Search" class="form-control autocomplete " />
</span>
</div>
}
</div>
To achieve this you can use the select event to amend the value to be placed in to the input. Try this:
$("#id").autocomplete({
// your settings...
select: function(e, ui) {
e.preventDefault();
$('#id').val(ui.item.label.split('|')[0].trim());
}
});
I am using select2-jquery to bring several items from the server (ajax) and the allow the user to select several of them, it works fine but I cannot select any given tag more than once and that's a requirement I'll paste some of my code, hopefully it helps. I have inspected the ajax requests and i can see the same data getting back from the server under the same search terms, but once an item is selected the select2 does NOT displays it anymore
This is a part of my View:
<div class="form-group">
#Html.LabelFor(m => m.Vals, T("Values"), new { #class = "control-label col-md-2" })
<div class="col-md-7">
<input id="Values" name="Values" type="hidden" style="width: 100%" data-url="#Url.Action("Action", "Controller")" />
</div>
</div>
And this is the JS part:
$(function () {
var fullTemplateString = 'some template string';
var resultTemplateString = 'other template';
var $selectInput = $('#Values');
initilizeSelect2($selectInput, fullTemplateString, resultTemplateString);
});
function initilizeSelect2($selectInput, fullTemplate, resultTemplate) {
$selectInput.select2({
placeholder: "Select Labs",
minimumInputLength: 2,
multiple: true,
tokenSeparators: [","],
tags: false,
ajax: {
url: $selectInput.data('url'),
dataType: 'json',
quietMillis: 250,
data: function(term, page) {
return {
term: term,
};
},
results: function(data, page) {
return {
results: data
};
}
},
formatSelection: function (item) {
return format(item, resultTemplate);
},
formatResult: function (item) {
return format(item, fullTemplate);
},
escapeMarkup: function (m) { return m; }
});
}
function format(item, templateString) {
var result = templateString
.replace(/\^\^id\^\^/g, item.id)
.replace(/\^\^icon\^\^/g, item.icon)
.replace(/\^\^text\^\^/g, item.name)
.replace(/\^\^desc\^\^/g, item.desc);
return result;
}
I am using select2 version:3.4.5 extensively in this project so any changes in this regard would be very painful
Thanks in advance
after a lot of search and debugging through the select2 code i found a way (hack) to pull this out by removing the css class .select2-selected that prevents already selected elements from displaying again. I know this isn't the best solution there is, but it is working now. I really welcome any improvements or better solutions
I'm a newbie to AngularJS with some fair knowledge with KnockoutJS also.
I'm trying to implement a search feature on 'products' in my ViewModel that is configurable by the end user by combining..
Search by 'name' of product
Search by 'tags' of product
in combination with search operations
CONTAINS
STARTS WITH
EQUALS
I believe you understood the functionality I am trying to build up.
The following is the ViewModel I'm using.
var InstantSearchController = function ($scope) {
var self = this;
$scope.filtersAvailable = [
{
displayText: 'Tag',
filterMethod: 'tagFilter',
description: 'Filter by Tags'
},
{
displayText: 'Description',
filterMethod: 'descriptionFilter',
description: 'Filter by description'
}
];
$scope.selectedFilter = $scope.filtersAvailable[1];
$scope.filterBehaviorsAvailable = [
{
displayText: 'CONTAINS',
regexPrefix: '',
regexPostfix: ''
},
{
displayText: 'STARTS WITH',
regexPrefix: '^',
regexPostfix: ''
},
{
displayText: 'EQUALS',
regexPrefix: '^',
regexPostfix: '$'
}
];
$scope.selectedFilterBehavior = $scope.filterBehaviorsAvailable[0];
$scope.products = [
{
name: 'Household Product',
description: 'Description household',
tags: ['personal', 'home']
},
{
name: 'Office product',
description: 'Business equipments',
tags: ['office', 'operations', 'business']
},
{
name: 'Misc products',
description: 'Uncategorized items',
tags: ['noclass']
}
];
}
Now, the following is my filters list.
var app = angular.module('InstantSearchModule', []);
//FILTERS BEGIN
app.filter('descriptionFilter', function () {
var filterFunction = function (data, filterBy) {
if (filterBy == null || filterBy === '')
return data;
var filtered = [];
var regExp = new RegExp(filterBy, 'gi');
angular.forEach(data, function (item) {
if (item.description.match(regExp))
filtered.push(item);
});
return filtered;
};
return filterFunction;
});
app.filter('tagFilter', function () {
var tagFilter = function (data, filterBy) {
if (filterBy == null || filterBy === '')
return data;
var filtered = [];
var regExp = new RegExp('^' + filterBy, 'gi');
debugger;
angular.forEach(data, function (item) {
var isMatching = false;
angular.forEach(item.tags, function (t) {
isMatching = isMatching || (t.match(regExp) != null);
});
if (isMatching)
filtered.push(item);
});
return filtered;
};
return tagFilter;
});
// FILTERS END
I have created a working part to configure search criteria including the 'filterString'(in a textbox), search operand[tags or description](with a select list) and a search mode[starts with / contains / equals](with another select list). Both of the filters are working fine if I specify the filter functions (tagFilter or descriptionFilter) directly in AngularJS directives as follows [JSFiddle Here].
<div data-ng-repeat="p in products|tagFilter:filterString|orderBy:'description.length'">
<h4 style="margin-bottom: 5px">{{$index+1}}. {{p.name}}</h4>
<div>
{{p.description}}
<button data-ng-repeat="t in p.tags|orderBy:'toString()'">{{t}}</button>
</div>
</div>
I was expecting the following to work for me as {{selectedFilter.filterMethod}} is rendering the value successfully, but is showing an error. Please see the HTML I tried to use for it.JSFiddle Here
<div data-ng-repeat="p in products|{{selectedFilter.filterMethod}}:filterString|orderBy:'description.length'">
<h4 style="margin-bottom: 5px">{{$index+1}}. {{p.name}}</h4>
<div>
{{p.description}}
<button data-ng-repeat="t in p.tags|orderBy:'toString()'">{{t}}</button>
</div>
</div>
I have attached the error I'm receiving in Google Chrome developer tools along with the resultant HTML to the subject. Please see below.
As you can see in the HTML, the filter method is not resolved and so, its not working for me. Do you guys have an advice what I am doing wrong?
If I understand it correctly all you need is a way to dynamically change filters. Everything else seems to be working.
I dont think you can use the syntax you are trying to use but you can make a third filter that injects the two others and chooses the right one depending on the parameters you send in.
New filter:
app.filter('multiFilter', function (descriptionFilterFilter, tagFilterFilter) {
var filterFunction = function (data, filterBy, filterRegExp, selectedFilter) {
if(selectedFilter.displayText === 'Description') {
return descriptionFilterFilter(data, filterBy, filterRegExp);
}
else {
return tagFilterFilter(data, filterBy, filterRegExp);
}
};
return filterFunction;
});
As you can see it also takes the filterRegExp and the selectedFilter as parameters. I also changed your old filters to take selectedFilter as a parameter.
Also notice that you have to append "Filter" to the filter name in order to inject it.
You call the new filter like this
multiFilter:filterString:filterRegExp:selectedFilter
So the div could loke something like this
<div data-ng-repeat="p in products|multiFilter:filterString:filterRegExp:selectedFilter|orderBy:'description.length'"
title="{{selectedFilter.filterMethod}}">
<h4 style="margin-bottom: 5px">{{$index+1}}. {{p.name}}</h4>
<div>
I made a working fork of your fiddle
Your fiddle is not working and has other error but, the reason filters are not loading is that you have used global controller function and not registered with your app module for the injection to work. Your filter belong to module InstantSearchModule but you controller does not.
Try the module registration syntax
app.controller('InstantSearchController',function($scope) {
});
see the Angular guide on controller https://code.angularjs.org/1.2.15/docs/guide/controller
Update: As it turns out the issue is not with dependency injection. It is because you cannot use expression to dynamically change filter. When i set to fixed filter it works fine
<div data-ng-repeat="p in products|descriptionFilter:filterString|orderBy:'description.length'"
title="{{selectedFilter.filterMethod}}">
You would have to either combine then or find a way to do select filtering.
See my fix here
http://jsfiddle.net/cmyworld/pW9EZ/1/
I am trying to implement a generic ASP.net MVC view. The UI should display a list of available and selected items loading data (basically list of string) from server. User can make changes into the list i.e. can select new items from available item list and also can remove items from selected list.
I wanted to do it using KnockoutJS as to take advantage of binding.
I manage to complete it upto the point everything is working except showing selected item as checked when the view is initialized in available list. E.g. As Shown Here
I tried various options (using template (closest to what I want to achieve), Checked attr, possible options), the issue is if I manage to display item checked some other functionality breaks. Tried defining a template but could not get it to work in my case.
HTML:
<div class='moverBoxOuter'>
<div id='contactsList'>
<span data-bind="visible: availableItems().length > 0">Available countries: </span>
<ul data-bind="foreach: availableItems, visible: availableItems().length > 0">
<li>
<input type="checkbox" data-bind="checkedValue: $data, checked: $root.selectedItems" />
<span data-bind="text: title"></span>
</li>
</ul>
<span data-bind="visible: selectedItems().length > 0">Selected countries: </span>
<ul data-bind="foreach: selectedItems, visible: selectedItems().length > 0">
<li>
<span data-bind="text: title"></span>
Delete
</li>
</ul>
</div>
JS:
var initialData = [
{
availableItems: [
{ title: "US", isSelected: true },
{ title: "Canada", isSelected: false },
{ title: "India", isSelected: false }]
},
{
selectedItems: [
{ "title": "US" },
{ "title": "Canada" }
]
}
];
function Item(titleText, isSelected) {
this.title = ko.observable(titleText);
this.isSelected = ko.observable(isSelected);
}
var SelectableItemViewModel = function (items) {
// Data
var self = this;
self.availableItems = ko.observableArray(ko.utils.arrayMap(items[0].availableItems, function (item) {
return new Item(item.title, item.isSelected);
}));
self.selectedItems = ko.observableArray(ko.utils.arrayMap(items[1].selectedItems, function (item) {
return new Item(item.title, item.isSelected);
}));
// Operations
self.selectItem = function (item) {
self.selectedItems.push(item);
item.isSelected(!item.isSelected());
};
self.removeItem = function (removedItem) {
self.selectedItems.remove(removedItem);
$.each(self.availableItems, function (item) {
if (item.title === removedItem.title) {
item.isSelected = false;
}
});
};
}
var vm = new SelectableItemViewModel(initialData);
$(document).ready(function () {
ko.applyBindings(vm);
});
Could you please help, see jsfiddle below:
http://jsfiddle.net/sbirthare/KR4a6/6/
**Update: Follow up question below **
Its followup question:
I need to add a combobox on same UI e.g. for US state. The available items are counties, based on user selection in state combo I need to filter out counties. I am getting data from server using AJAX and its all successful BUT the displayed list is not refreshing. I was expecting having binding setup correctly, if we change the observable array in viewmodel, the UI should change. I tried forcing change to availableItems but it just display all items. Please see if you can spot the problem in below code where I am updating ViewModel observable array.
function multiselect_change() {
console.log("event: openmultiselect_change");
var selectedState = $("#stateDropdownSelect").val();
var propertyName = $("#PropertyName").val();
var searchId = #Model.SearchId;
var items;
var model = { propertyName: propertyName, searchId: searchId, stateName: selectedState };
$.ajax({
url: '#Url.Action("GetFilterValues", "Search")',
contentType: 'application/json; charset=utf-8',
type: 'POST',
dataType: 'html',
data: JSON.stringify(model)
})
.success(function(result) {
debugger;
items = JSON.parse(result);
vm.availableItems(items.AvailableItems);
//vm.availableItems.valueHasMutated();
//var item = document.getElementById('availableItemId');
//ko.cleanNode(item);
//ko.applyBindings(vm, item);
vm.filter(selectedState);
})
.error(function(xhr, status) {
alert(status);
});
}
As user3426870 mentioned, you need to change the value you passed to the checked binding to boolean.
<input type="checkbox" data-bind="checkedValue: $data, checked: isSelected" />
Also, I don't think you need to have selectedItems in the initial data.
Instead in the viewModel, you can do something like:
self.selectedItems = ko.computed(function() {
return ko.utils.arrayFilter(self.availableItems(), function (item) {
return item.isSelected();
});
});
It's because you give an array to the binding checked while it's supposed to be a value comparable to true or false (like undefind or an empty string).
I would use a function checking if the $data is in your array and returning a boolean to your binding.
Something like that!