I noticed some weird behavior in all comboboxes in my application and after some time I noticed that the Kendo UI ComboBoxes are making or firing the change event two times and so they make two http requests if the code inside has one
I searched alot but found nothing to help
I use comboboxes with angularjs k-options (for general options) and k-on-change attribute for the change event handler
I tried to implement the combo box without angularjs attributes just as normal usage of the kendo ui combobox and it gave the same behavior
I didn't use alert for debugging this issue and used console.log for it
I used fiddler to watch for http requests and found that any change has two requests
I even tried and changed the requests to post and params to data but the same issue was found too
code sample:
html;
<select id="id" kendo-combo-box k-options="options" k-on-change="change(kendoEvent)" class="class" required></select>
code in 'script tag'
var app = angular.module('app', ['blockUI', 'kendo.directives']);
app.controller("controller",
function($scope, $http) {
$scope.GetAllData = function() {
$scope.comboDataSource = new kendo.data.DataSource({
data: #Html.Raw(Json.Encode(ViewBag.listFromC#)) // before loading view we're assigning the viewbag with alist of data
});
$scope.options = {
autoWidth: true,
filter: "contains",
ignoreCase: true,
placeholder: "Choose ...",
syncValueAndText: true,
dataTextField: "Name",
dataValueField: "Id",
dataSource: $scope.comboDataSource
};
}
}
$scope.change = function (kendoEvent) {
// kendoEvent.preventDefault(); // this line was added to test if it will prevent the second request or change event firing
console.log('change fired');
var cbAnother = $("#cbAnother").data("kendoComboBox"); // those two lines has no effect if removed
cbAnother.setDataSource([]);
if (!kendoEvent.sender.value()) { // this if statement has no effect if removed
return;
}
$http({
method: "get",
url: "#Url.Action("Action", "MVCControler", new {area = "Area"})",
params: { Id: kendoEvent.sender.value() }
}).then(function(response) {
var dataS = new kendo.data.DataSource({
data: response.data.ourData
});
$("#cbAnother").data("kendoComboBox").setDataSource(dataS);
},
function() {
....
}
);
};
rest of code ....
i'm pretty sure I'm ending all braces right
I found it was a bug so I rolled back to previous version and it went great.
Related
In my partial view I have a dialog box and a fancy tree is rendered. From the view on the list box change event I load the tree. When the tree is loaded I check to see if cache exists and if it does I pull from cache and if not then build and add the list into cache.
Cache itself is working correctly, but the method which pulls data to a list to be added to cache seems to pull older values. Since this method is trigged by ajax on this view, I suspect the issues lies within, I have tried to set no cache attribute in controller action method as well as sending a hard code cache bust paramater but to no avail.
JS Listbox change event
$('#SystemID').change(function () {
var userroleid = $("#UserRoleID").val();
// if (userroleid != 1) {
$("#treeview").remove();
$("#partTreeView").remove();
var overlay = $('<div></div>').prependTo('body').attr('id', 'overlay');
$.ajax({
type: 'POST',
url: serviceEntryURL,
cache: false,
datatype: "html",
data: $("#form").serialize(),
success: function (result) {
$("#main").html(result);
overlay.remove();
}
});
});
View Rendering the Tree
<div id="errorCodes">
#Html.RenderTree(CacheHelper.ErrorCodes(#Model.ErrorCodeType), ec => ec.Name, ec => ec.Children.ToList(), ec => (ec.ID).ToString(), Model.ErrorCodes, "error")
</div>
Cache Helper
if (HttpRuntime.Cache[cacheKeyRemove] != null)
{
ERRORCODES = (List<Domain.Lists.ErrorCode>)HttpRuntime.Cache[cacheKeyRemove];
}
else
{
**//The following method GlobaList.ErrorCodes is not cached or anything but it still returns
older values. **
ERRORCODES = RunLog.Domain.Lists.GlobalList.ErrorCodes(instrumentTypeID);
HttpRuntime.Cache.Add(cacheKeyRemove, ERRORCODES, null, DateTime.Now.AddHours(10), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
}
Error Code Edit Page
If I go to this view and edit the error code and the cache key is removed successfully. When I go back to the view where i render tree, since this cache was removed, it queries the above method to build the error code list but the value I had just edited is not the correct and the old one. Whats even more weird is if I add a new record to my error code table and cache is reset, then the new record shows up correctly in the other view.
while (enumerator.MoveNext())
{
if (enumerator.Key.ToString() == cacheKeyRemove)
{
HttpContext.Cache.Remove(enumerator.Key.ToString());
}
}
I experienced such error one time, It was a caching problem. In order to solve this problem, each time I send a new ajax request, I appended the url with a new random number.
Hope this helps you.
for example suppose the url is:
http://localhost/app1/getData?id=randomNb
I have five dropdownlists in form of html selects. The first binds at page load using jQuery, and the rest bind when the previous dropdown has been selected. I also have five hidden fields for each dropdown which stores the selected values.
My problem is that when I do a post back, i.e. click the "Search" button, I have to re-populate the dropdowns and select the correct values again by using the ID's in the hidden fields. So far, I've come up with no good way to do this.
In the .aspx page:
<select name="boxFunktionsnedsattning" id="boxFunktionsnedsattning" multiple="multiple </select>
<asp:TextBox ID="HiddenBoxFunktionsnedsattning" runat="server" />
<script type="text/javascript">
function boxFunktionsnedsattningPopulate() {
$.ajax({
type: "POST",
url: "Sok.aspx/getFunktionsnedsattningar",
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: LoadBoxFunktionsnedsattning,
failure: function (response) {
alert(response);
}
});
}
//============================================================================================================
function LoadBoxFunktionsnedsattning(response) {
var result = response.d;
var options = $("#boxFunktionsnedsattning");
options.text(''); // clear the box content before reloading
if ($('#boxFunktionsnedsattning').val != '') {
options.removeAttr("disabled");
options.multipleSelect("enable");
}
else {
options.attr("disabled", true);
options.multipleSelect("disable");
}
$.each(result, function () {
options.append($("<option />").val(this.id).text(this.name));
});
UpdateBoxEnabledState();
options.multipleSelect("refresh");
}
</script>
Backend code:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static Funktionsnedsattning[] getFunktionsnedsattningar()
{
GetDataService.IgetDataClient gdc = new IgetDataClient();
return gdc.getFunktionsnedsattningAll();
}
I should add that I'm a beginner when it comes to jQuery, so there is probably something I've overlooked.
IF your using webforms use an onclick function to post back to the server instead of a submit. I think this is the functionality you want because the variables in the inputs of the form will keep its value. Is the search button returning results on the same page or a different one because it will determine the ease in which you can keep varibles during a post back. Good luck!
Got it working with the following solution:
function fillFunktionsnedsattning() {
//stores the value of selected items
var $fn = $('#<%=HiddenBoxFunktionsnedsattning.ClientID%>');
//creates an array of the values in the hidden field
var fnSplit = $fn.val().split(",");
//val() accepts an array which it uses to select items in the list (go figure)
$("#boxFunktionsnedsattning").val(fnSplit);
$("#boxFunktionsnedsattning").multipleSelect("refresh");
//function that triggers the binding of the next dropdown
boxFunktionsnedsattningOnChange();
}
For it to work, this function needs to be called in the function that populates the dropdown. Each dropdown needs it's own fillFunction to be called in the same place, like this, for an example:
function LoadBoxFunktionsnedsattning(response) {
var result = response.d;
var options = $("#boxFunktionsnedsattning");
options.text(''); // clear the box content before reloading
if ($('#boxFunktionsnedsattning').val != '') {
options.removeAttr("disabled");
options.multipleSelect("enable");
}
else {
options.attr("disabled", true);
options.multipleSelect("disable");
}
$.each(result, function () {
options.append($("<option />").val(this.id).text(this.name));
});
fillFunktionsnedsattning();
UpdateBoxEnabledState();
options.multipleSelect("refresh");
It's probably possible to simplify this, but this works for me.
I'm using Kendo UI Autocomplete with an ASMX Service which returns a string array like this :
<ArrayOfString>
<string>One string</string>
...
</ArrayOfString>
All works fine except that the items list opens twice. One click close one list and the "second behind" is still open.
When the list's opening we can see the second list opens behind the first.
Any idea ?
JS Code:
<input id="autoCompleteTest" />
<script>
var dataSource = new kendo.data.DataSource({
serverFiltering: true,
transport: {
read: {
data: {
startswith: function(){
return $("#autoCompleteTest").data("kendoAutoComplete").value();
}
},
url: "WebService.asmx/GetStrings",
type: "POST",
}
},
schema: {
// specify the the schema is XML
type: "xml",
// the XML element which represents a single data record
data: "/ArrayOfString/string",
// define the model - the object which will represent a single data record
model: {
// configure the fields of the object
fields: {
// the "title" field is mapped to the text of the "title" XML element
value: "text()"
}
}
}
});
$("#autoCompleteTest").kendoAutoComplete({
minLength: 3,
dataValueField : "value",
dataTextField : "value",
dataSource: dataSource
});
</script>
C# Code:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public String[] GetStrings(string startswith)
{
using (var dataContext = new DataClassesDataContext())
{
var query = from x in dataContext.product where x.shortName.StartsWith(startswith) select x.shortName;
return query.ToArray();
}
}
I've run into a similar issue and posted here
Please confirm that your autocomplete control is not located inside of another control that forces the Kendo control to render a second time.
do you client code when dom is ready for kendo multiselect:
$(document).ready(function () {
..yourcode.});
see: http://docs.telerik.com/kendo-ui/controls/editors/multiselect/overview#accessing-an-existing-multiselect
I have an ASP .NET MVC application, additonally I am using Knockout 2.0.0. I created a partial view which I would like to render to the page using knockout. The partial needs to be rendered within a Knockout foreach statement. I am unable to get the knockout HTML binding to work, and so I'm currently using a hack to put the html into the div using JQuery.
There is a lot of html on this page, so it's not possible to post all of the source code, so I will try and post the pertinent code:
<div data-bind="foreach:issues">
#* SNIP - A lot of other html here*#
<div id="myPartialDiv" data-bind="html: $parent.getHtml(issueId())">
</div>
</div>
Further down I have the following javascript function on my KO View Model (I have commented out my hack and included the code that returns HTML):
var getHtml = function (issueId) {
var baseUrl = '#Url.Action("GetHtmlAction","MyController")';
$.ajax(
{
type: "POST",
url: baseUrl,
data: "&issueId=" + issueId,
success: function (data) {
//$('#mypartialDiv').html(data);
return data;
},
error: function (req, status, error) {
//$('#myPartialDiv').html('Something went wrong.');
return 'Something went wrong.'
},
dataType: "text"
});
}
The code above results in no data being rendered to the page. USing Chrome debug tools, I see that there are no javascript errors occuring, and knockout is simply not binding the html of the div to the results returned from the getHtml function.
What am I doing wrong?
Thanks
As Miroslav Popovic explains, the problem is that the AJAX request is asynchronous, so the return data is ignored and there is no return value from your call to getHtml.
I would suggest using a custom binding that handles the asynchronous HTML loading (I've put a working example here).
This works by taking 2 parameters to the asyncHtml: a function to call that takes a success callback as it's final parameter (plus any other parameters) and an array of the parameters that need to be passed to that function.
<div id="myPartialDiv" data-bind="asyncHtml: { source: getHtml, params: [123] }">Loading...</div>
The custom binding then grabs these values, concats a custom callback onto the parameters that are passed to it, and calls the specified function:
ko.bindingHandlers.asyncHtml = {
init: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
var parameters = value.params.concat([function(data) {
$(element).html(data);
}]);
value.source.apply(null, parameters);
}
};
Finally we can re-implement our view model HTML-retrieving method to make the POST call and invoke the new success handler:
var ViewModel = function() {
this.getHtml = function(issueId, callback) {
$.ajax(
{
type: "POST",
url: "/echo/html/",
data: {
html: "<p>server response " + issueId + "</p>",
delay: 1
},
success: callback,
dataType: "text"
});
};
};
Note: for this example I am using the jsFiddle echo to post back a random response
$.ajax is an asynchronous call. When you call it, the execution will just continue to the next statement in the getHtml function. Since this is the last statement, the getHtml function will return undefined.
About your return data;... This return is within a success callback function. The data will be result of that function, not the parent getHtml function. Besides, getHtml is already completed. You can't return a result from it.
How about having an observable property in your view model called html, and then find some other means of triggering the getHtml function (button click, some other success callback, issueId property change...), that will in turn set the 'html' property value. Then you could simply data-bind to that property data-bind="html: html".
I have created a javascript context menu using Jquery that works perfectly. But there are two options. The first one is to create this context menu in C# (If that's possible). The second way is to run a C# Function when a button in the menu is clicked. Which option is the best and how do i start? Kind regards
Javascript:
function Menu($div){
var that = this,
ts = null;
this.$div = $div;
this.items = [];
// create an item using a new closure
this.create = function(item){
var $item = $('<div class="item '+item.cl+'">'+item.label+'</div>');
$item
// bind click on item
.click(function(){
if (typeof(item.fnc) === 'function'){
item.fnc.apply($(this), []);
}
})
// manage mouse over coloration
.hover(
function(){$(this).addClass('hover');},
function(){$(this).removeClass('hover');}
);
return $item;
};
this.clearTs = function(){
if (ts){
clearTimeout(ts);
ts = null;
}
};
this.initTs = function(t){
ts = setTimeout(function(){that.close()}, t);
};
}
// add item
Menu.prototype.add = function(label, cl, fnc){
this.items.push({
label:label,
fnc:fnc,
cl:cl
});
}
// close previous and open a new menu
Menu.prototype.open = function(event){
this.close();
var k,
that = this,
offset = {
x:0,
y:0
},
$menu = $('<div id="menu"></div>');
// add items in menu
for(k in this.items){
$menu.append(this.create(this.items[k]));
}
// manage auto-close menu on mouse hover / out
$menu.hover(
function(){that.clearTs();},
function(){that.initTs(3000);}
);
// change the offset to get the menu visible (#menu width & height must be defined in CSS to use this simple code)
if ( event.pixel.y + $menu.height() > this.$div.height()){
offset.y = -$menu.height();
}
if ( event.pixel.x + $menu.width() > this.$div.width()){
offset.x = -$menu.width();
}
// use menu as overlay
this.$div.gmap3({
action:'addOverlay',
latLng: event.latLng,
content: $menu,
offset: offset
});
// start auto-close
this.initTs(5000);
}
// close the menu
Menu.prototype.close = function(){
this.clearTs();
this.$div.gmap3({action:'clear', name:'overlay'});
}
Well you could create a server control in C# and emit the menu from it, but since you already have a working menu it's just easier to call a server-side method in response to a click. If you're using jQuery it's as easy as:
$.ajax({
url: "/Path/To/MyMethod",
type: "POST",
dataType: "JSON",
data: <some POST data>,
contentType: "application/json; charset=utf-8",
success: function (result) {
// Do your stuff here
},
error: function (jqXHR, textStatus, errorThrown) {
// Report error
}
});
The implementation of the server-side part can be either a static [WebMethod] in an ASPX page, or if you're using MVC then it can be a direct call to a controller method.
I am assuming what you are trying to do is call a c# method when an Item on the context menu is selected. If you are using an MVC model this is pretty easy to do. Use a call as follows passing the parameters in JSON format. I am just using a skeleton method from my code as an example you would call LibraryRead method when you click on the Context Menu Link
Client Side
function LibraryRead() {
$.ajax({
url : 'Library/ReadLibrary',
type : "POST",
data : JSON.stringify(idLibrary),
dataType : "json",
contentType : "application/json; charset=utf-8",
success : function(result) {
$(result).each(function() {
....Process Results
});
},
error : function() {
.....If something goes wrong, if you use a try catch in your code
which does not handle the exception correctly and something goes wrong
this will not be triggered. Use propper exception handling.
}
});
}
Server Side
// Post: /Library/ReadLibrary
[HttpPost]
public JsonResult ReadLibrary(int idLibrary)
{
try
{
var library = READ your library here from your data source
return this.Json(library);
}
else
{
return null;
}
}
catch (Exception ex)
{
//Exception handling omitted for simplicity
}
}
Do a search on google for MVC3 and JQuery / Javascript calls with JSON, there are loads of resources available.
If you are not using MVC pattern you may be able to use a web service or method in the code behind. You need to add the appropriate attribute over the method though like [Ajax.AjaxMethod()] or [WebMethod]