I've set up typeahead to return search results. the results are returning correctly, however the expected functionality of being able to press the up and down buttons to cycle through the search results, to autocomplete the text box is not working. I cant figure out why.
var items = [{"Name":"TestAccount", "AccountID":"TestID"},{"Name":"TestAccount2", "AccountID":"TestID2"}]
var templ = Hogan.compile('<div class="search-result">{{Name}}</div>');
var myTA = $('.js-header-search-box').typeahead({
hint: true,
highlight: true,
minLength: 1
}, {
name: "Accounts",
valueKey: "AccountID",
engine: Hogan,
templates: {
empty: [
'<div class="empty-message">',
'unable to find any items that match the current query',
'</div>'
].join('\n'),
suggestion: function (data) { return templ.render(data); }
},
source: function (query, process) { process(items);
}
});
myTA.on('typeahead:selected', function (obj, datum) {
var id = datum['AccountID'];
document.location.href = area + '/Account/Edit' + id + '/';
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="http://twitter.github.io/hogan.js/builds/3.0.1/hogan-3.0.1.js"></script>
<script src="https://twitter.github.io/typeahead.js/releases/latest/typeahead.bundle.js"></script>
<input autocomplete="off" class="js-header-search-box header-search-box" placeholder="Account name or postcode" type="text" >
You need to use displayKey for that. Something like below
displayKey: function(accnt){
return accnt.Name;
}
displayKey – For a given suggestion object, determines the string representation of it. This will be used when setting the value of the input control after a suggestion is selected. Can be either a key string or a function that transforms a suggestion object into a string. Defaults to value.
Here is the reference
Here is a DEMO
Related
I'm using Google Maps autocomplete feature and everything is working fine.
But I'd like to know if it's possible to run .getPlace() function from a custom string, wether it's coordinates or address. For example, instead of using an input field and click on the location to select it, I'd like to call it manually, like this:
var myAutoComplete = new google.maps.places.Autocomplete('City, Country');
And it return the same as a normal autocomplete. The reason why I want to do this, is because somethis I get users location from html5 geolocation (or other method) and I'd like to run the getPlace function with that data.
The getPlace function from google return a more complete set of data, with all the names, coordinates, pictures from that city, etc..
By the way, I'm using Google Maps with AngularJs with this module: ngMap.
Edit: Posting the code I have so far as requested on the comments.
//HTML
<input places-auto-complete on-place-changed="vm.placeChanged()" />
//Controller
function MainController(NgMap) {
var vm = this;
vm.placeChanged = function() {
var param = {
maxWidth: 1920,
maxHeight: 1080
};
var autocomplete = this.getPlace();
console.log('Result: ', autocomplete);
console.log(autocomplete.geometry.location.lat());
console.log(autocomplete.geometry.location.lng());
console.log(autocomplete.photos[0].getUrl(param));
}
}
The input automatically generate the autocomplete feature, when I select one address option, the function is called and I get all the response correctly.
What I want is to call the same function, but instead of using the autocomplete from google, I want to pass my own string and return the same data as the function.
As suggested on the comments, I tried using a custom directive to run the same autocomplete, this is my plunkr: http://plnkr.co/edit/hcRXJxB7ItN6YtISWdx3?p=preview
Autocomplete object does not support such kind of scenario, it could only be attached to the specified input text field from where the user selects the item and the correspinding place is returned.
Instead you could utilize AutocompleteService class which in my opinion suits your scenario very closely
According to official documentation AutocompleteService class
does not add any UI controls. Instead, it returns an array of
prediction objects, each containing the text of the prediction,
reference information, and details of how the result matches the user
input. This is useful if you want more control over the user interface
than is offered by the Autocomplete
The following example demonstrates how to return the details of the Place from input string entered in text box
Example
var app = angular.module('myApp', ['ngMap']);
app.controller('MyCtrl', function ($scope,NgMap) {
var vm = this;
vm.center = [0,0];
vm.types = "['establishment']";
NgMap.getMap().then(function (map) {
vm.map = map;
});
vm.addressResolved = function (value) {
$scope.$apply(function () {
vm.address = value.address_components;
vm.center = value.geometry.location;
});
}
});
app.directive('myComplete', function (NgMap) {
return {
restrict: 'A',
scope: {
map: '=',
addressResolved: '&addressResolved'
},
link: function (scope, element, attrs) {
// on blur, update the value in scope
element.bind('blur', function (blurEvent) {
var service = new google.maps.places.AutocompleteService();
service.getQueryPredictions({ input: element.val() }, function (predictions, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
if (predictions.length > 0) {
element.val(predictions[0].description);
var service = new google.maps.places.PlacesService(scope.map);
service.getDetails({
placeId: predictions[0].place_id
}, function (place, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
scope.addressResolved({ place: place });
}
});
}
}
});
});
}
};
});
<script src="https://maps.google.com/maps/api/js?libraries=placeses,visualization,drawing,geometry,places"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="https://rawgit.com/allenhwkim/angularjs-google-maps/master/build/scripts/ng-map.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl as vm">
Auto Complete Type:
<select ng-model="vm.types">
<option value="['geocode']">Geodode</option>
<option value="['establishment']">Establishment</option>
<option value="['address']">Address</option>
</select><br/>
<h3>Custom directive usage</h3>
<input my-complete address-resolved="vm.addressResolved(place)" map="vm.map" />
address : <pre>{{vm.address | json}}</pre>
<ng-map zoom="12" center="{{vm.center}}"></ng-map>
</div>
Demo
I have input field which I am using for autocomplete and populate on the fly by executing http requests. I am getting such object as example:
{
id:1,
name:'ABC'
}
I want to display name for a end user but later on when input has been selected I want to use it as id in my further processing. But ng-model converts my object into the string and I loose my id.
In general all works fine but my issue is that when user select something, lets say string "ABC" it means nothing for me unless I can tied it to "ID" which has been returned by my API. Only if I know ID I can continue future processing.
Could you please help me to figure out, what should I do in order to capture fromSelected as object but still show friendly text to user?
Thanks for any help!
Code:
HTML:
<input type="text" ng-model="fromSelected" placeholder="Country, city or airport" typeahead="place.readableName for place in getPlace($viewValue, 'en')" typeahead-loading="loadingLocations" typeahead-no-results="noResults" class="form-control">
JS:
app.controller('PlaceController', function($scope, $http, searchData) {
$scope.fromSelected = '';
$scope.toSelected = '';
$scope.$watch('fromSelected', function(newValue, oldValue){
if (newValue !== oldValue) searchData.setTravelFrom(newValue);
});
$scope.$watch('toSelected', function(newValue, oldValue){
if (newValue !== oldValue) searchData.setTravelTo(newValue);
});
// Any function returning a promise object can be used to load values asynchronously
$scope.getPlace = function(term, locale) {
return $http.get('http://localhost:8080/api/places/search', {
params: {
term: term,
locale: locale
}
}).then(function(response){
return response.data.map(function(item){
return {
'id': item.id,
'name': item.name,
'readableName': item.name + ' (' + item.id + ')'
};
});
});
};
});
I'm using select2 for tagging and I have it setup such that a user can add new tags as well. The issue that I'm dealing with is validating the user entry and adding the sanitized tag to selection.
To be more specific, when a user enters a space in a tag, i use formatNoMatches to display a js link to sanitize the tag and then add the tag programmatically. This code seems to run without errors but when sanitize is called all selections of the input are cleared.
Any clues where i might be going wrong?
var data=[{id:0,tag:'enhancement'},{id:1,tag:'bug'},{id:2,tag:'duplicate'},{id:3,tag:'invalid'},{id:4,tag:'wontfix'}];
function format(item) { return item.tag; }
function sanitize(a){
$("#select").select2('val',[{
id: -1,
tag: a
}]);
console.log(a);
};
$("#select").select2({
tags: true,
// tokenSeparators: [",", " "],
createSearchChoice: function(term, data) {
return term.indexOf(' ') >= 0 ? null :
{
id: term,
tag: term
};
},
multiple: true,
data:{ results: data, text: function(item) { return item.tag; } }, formatSelection: format, formatResult: format,
formatNoMatches: function(term) { return "\"" + term + "\" <b>Is Invalid.</b> <a onclick=\"sanitize('"+ term +"')\">Clear Invalid Charecters</a>" }
});
Only this solution works for me:
function convertObjectToSelectOptions(obj){
var htmlTags = '';
for (var tag in obj){
htmlTags += '<option value="'+tag+'" selected="selected">'+obj[tag]+'</option>';
}
return htmlTags;
}
var tags = {'1':'dynamic tag 1', '2':'dynamic tag 2'}; //merge with old if you need
$('#my-select2').html(convertObjectToSelectOptions(tags)).trigger('change');
After hacking on it some more i realized that I should be setting the new item to the "data" property and not value.
var newList = $.merge( $('#select').select2('data'), [{
id: -1,
tag: a
}]);
$("#select").select2('data', newList)
You can set new value (if tags you can pass array) and trigger 'change' event.
var field = $('SOME_SELECTOR');
field.val(['a1', 'a2', 'a3']) // maybe you need merge here
field.trigger('change')
About events: https://select2.github.io/options.html#events
I have a column in a Kendo grid that I want to perform some specific logic for when rendering, and am using Angular. I have the grid columns set up using the k-columns directive.
After looking at the documentation, it seemed simple: I could add the template option to my column, define the function to perform my logic, and pass the dataItem value in. What I have looks something like this:
k-columns='[{ field: "Name", title: "Name",
template: function (dataItem){
// Perform logic on value with dataItem.Name
// Return a string
}
}]'
However, running this causes a syntax error complaining about the character '{' that forms the opening of the block in my function.
I have seen several examples of defining a template function in this format. Is there something else that needs to be done for this to work? Am I doing something incorrectly? Is there another way of defining the template as a function and passing the column data to it? (I tried making a function on my $scope, which worked, except I couldn't figure out how to get data passed into the function.)
Thank you for your help.
It appears that defining a column template in this fashion isn't supported when using AngularJS and Kendo. This approach works for projects that do not use Angular (standard MVVM), but fails with its inclusion.
The workaround that a colleague of mine discovered is to build the template using ng-bind to specify a templating function on the $scope, all inside of a span:
template: "<span ng-bind=templateFunction(dataItem.Name)>#: data.Name# </span>"
This is the default column templating approach that is implemented by Telerik in their Kendo-Angular source code. I don't know yet if the data.Name value is required or not, but this works for us.
Warning: Don't have access to Kendo to test the code at the moment, but this should be very close
In your case, you are assigning a a string to the value of k-columns and that string contains the the word function and your curly brace {
You need to make sure the function gets executed ... something like this:
k-columns=[
{
field: "Name",
title: "Name",
template: (function (dataItem){
// Perform logic on value with dataItem.Name
// Return a string
}())
}
];
Note the difference:
We create an object -- a real honest-to-goodness object, and we use an IIFE to populate the template property.
Maybe, it will be useful for someone - this code works for me too:
columns: [
{
field: "processed",
title:"Processed",
width: "100px",
template: '<input type="checkbox" ng-model="dataItem.processed" />'
},
and you get the two-way binding with something like this:
<div class="col-md-2">
<label class="checkbox-inline">
<input type="checkbox" ng-model="vm.selectedInvoice.processed">
processed
</label>
</div>
This can be done via the columns.template parameter by supplying a callback function whose parameter is an object representing the row. If you give the row a field named name, this will be the property of the object you reference:
$("#grid").kendoGrid({
columns: [ {
field: "name",
title: "Name",
template: function(data) {
return data.name + "has my respect."
}
}],
dataSource: [ { name: "Jane Doe" }, { name: "John Doe" } ]
});
More information is available on Kendo's columns.template reference page.
After hours of searching. Here is the conclusion that worked:
access your grid data as {{dataItem.masterNoteId}} and your $scope data as simply the property name or function.
Example
template: '<i class="fa fa-edit"></i>',
I really hope this safes somebody life :)
just use like my example:
}, {
field: "TrackingNumber",
title: "#T("Admin.Orders.Shipments.TrackingNumber")",
//template: '<a class="k-link" href="#Url.Content("~/Admin/Shipment/ShipmentDetails/")#=Id#">#=kendo.htmlEncode(TrackingNumber)#</a>'
}, {
field: "ShippingMethodName",
title: "#T("Admin.Orders.Shipments.ShippingMethodName")",
template:function(dataItem) {
var template;
var ShippingMethodPluginName = dataItem.ShippingMethodPluginName;
var IsReferanceActive = dataItem.IsReferanceActive;
var ShippingMethodName = dataItem.ShippingMethodName;
var CargoReferanceNo = dataItem.CargoReferanceNo;
var ShipmentStatusId = dataItem.ShipmentStatusId;
if (ShipmentStatusId == 7) {
return "<div align='center'><label class='label-control'><b style='color:red'>Sipariş İptal Edildi<b></label></div>";
} else {
if (ShippingMethodPluginName == "Shipping.ArasCargo" || ShippingMethodPluginName == "Shipping.ArasCargoMP") {
template =
"<div align='center'><img src = '/content/images/aras-kargo-logo.png' width = '80' height = '40'/> <label class='label-control'><b>Delopi Aras Kargo Kodu<b></label>";
if (IsReferanceActive) {
template =
template +
"<label class='label-control'><b style='color:red; font-size:20px'>"+CargoReferanceNo+"<b></label></div>";
}
return template;
}
I am trying to find out why the filter function isn't working, but I am stucked. This is the first time I am using Dojo but I am not really familliar with that framework. I am trying and searching for maybe 2 or 3 hours but I can't find a solution.
Waht I want, is to implement a filter or search mechanism. But it is not working, yet...
This is my code:
dojo.require('dojo.store.JsonRest');
dojo.require('dijit.layout.ContentPane');
dojo.require("dijit.form.Button");
dojo.require('dojox.grid.DataGrid');
dojo.require('dojo.data.ObjectStore');
dojo.require('dijit.form.TextBox');
dojo.require('dojox.data.AndOrReadStore');
dojo.require('dojo._base.xhr');
dojo.require('dojo.json')
dojo.require('dojo.domReady');
dojo.ready(
function(){
var appLayout = new dijit.layout.ContentPane({
id: "appLayout"
}, "appLayout");
var textBox = new dijit.form.TextBox({
name: "searchbox",
placeHolder: "Search ..."
});
var filterButton = new dijit.form.Button({
label: 'Filter',
onClick: function () {
searchWord = textBox.get('value');
query = "id: '"+searchWord
+"' OR date_A: '"+searchWord
+"' OR dateB: '"+searchWord
+"' OR product: '"+searchword+"'";
grid.filter({complexQuery: query}, true);
}
});
store = new dojo.store.JsonRest({target:'products/'});
grid = new dojox.grid.DataGrid(
{
store:dojo.data.ObjectStore({objectStore: store}),
structure:
[
{name:'id', field: 'id'},
{name:'date_A', field: 'dateA'},
{name:'date_B', field: 'dateB'},
{name:'product' , field: 'product'},
],
queryOptions: {ignoreCase: true}
});
textBox.placeAt(appLayout.domNode);
filterButton.placeAt(appLayout.domNode);
grid.placeAt(appLayout.domNode);
appLayout.startup();
}
);
Would be very nice if u can tell me what's wrong with this dojo code...
The result is, that the loading icon appears and after a while the unfiltered data is shown... There is no exception thrown.
Thanks in advance.
Ok, I have solved it with the AndOrReadWriteStore. You can also use an AndOrReadStore. The problem was, that the JSON data wasn't in the right format. You can see the right format here: dojotoolkit.org/api/dojox/data/AndOrReadStore. The other change is: I used the url instead the data attribute inside the store. So finally it is working now. Thx anyway.
Here's an example of a filter that uses both an AND and an OR:
grid.filter("(genre: 'Horror' && (fname: '" + searchWord + "' || lname:'" + searchWord + "'))")
So the users search word is filtered across fname and lname as an OR but it also searches for genre = Horror as an AND.
This document has other examples...
http://livedocs.dojotoolkit.org/dojox/data/AndOrReadStore