Kendo control value in the event is the controls previous value - asp.net-mvc

I am trying to understand why this isn't working. If i set the value of myTextBox to 5 then trigger the change event. the value for my myTextBox is null. If i change the value to 10 then fire the event again, the value will be the previous one (5). I've compared it to one of the many textboxes working on the form and they appear the same. The only difference is the value property in the wrapper object is set in the ones that work but behind in the one that doesn't. Digging into the both objects element property, i see the values are correct and current. Any help would be appreciated.
Model Property
[UIHint("Decimal")]
[Display(Name = "Example")]
public decimal? MyTxt{ get; set; }
Template (Decimal.cshtml):
#model decimal?
#{
var defaultHtmlAttributesObject = new { style = "width:100%" };
var htmlAttributesObject = ViewData["htmlAttributes"] ?? new { };
var htmlAttributes = Html.MergeHtmlAttributes(htmlAttributesObject, defaultHtmlAttributesObject);
}
#(Html.Kendo().NumericTextBoxFor(m => m)
.Format("#.00")
.HtmlAttributes(htmlAttributes)
)
UI Declaration
#Html.EditorFor(m => m.MyTxt, new { htmlAttributes = new { #style="width: 100%", #readonly = "readonly" } })
Javascript:
var myTextBox = $('#MyTxt').data('kendoNumericTextBox');
$(document).on('change', '#foo', function(){
var test = myTextBox.value();
})
Update:
In the document ready function i was binding the change event like this:
$('#MyTxt').change({ source: $('#MyTxt'), destination: someObject, isTwoMan: true, crewType: LaborType.Set }, SomeCalcFunction);
The jQuery change event fires nefore the kendo one thus the delay in getting the correct value. The fix was to read the manual and bind to the event the kendo way

the issue was in the way i was binding to the change event.
$('#MyTxt').change({ source: $('#MyTxt'), destination: someObject, isTwoMan: true, crewType: LaborType.Set }, SomeCalcFunction);
will fire before the kendo event does. Changing it the kendo way fixed my issue
$("#MyTxt").bind("change", function (e) {
var event = jQuery.Event('change', {
source: $("#MyTxt"),
destination: someObject,
isTwoMan: true,
crewType: LaborType.Set
});
SomeCalcFunction(event);
});

Related

Using Html.DropDownListFor as part of a paging solution in a razor view

I've spent hours on this, and I'm obviously missing something. Code extracts below are from a cut-down version of my actual app.
My viewmodel contains this:
public IEnumerable<SelectListItem> DisplayPageOptions { get; set; }
public string SelectedPageOption { get; set; }
private static SelectListItem item1 = new SelectListItem() { Text = "25", Value = "25" };
private static SelectListItem item2 = new SelectListItem() { Text = "50", Value = "50" };
private static SelectListItem item3 = new SelectListItem() { Text = "100", Value = "100" };
public SelectList selectList = new SelectList(new[] { item1, item2, item3 }, "Value", "Text", item1);
My razor view contains this:
#Html.DropDownListFor(m => m.SelectedPageOption, Model.DisplayPageOptions, "Pages to display", new { onchange = #"submit()" })
My controller contains this:
SymbolViewModel vm = SymbolViewModel.Instance;
if (vm.SelectedPageOption == null)
{
vm.SelectedPageOption = "25";
}
vm.DisplayPageOptions = vm.selectList;
SymbolDataService service = new();
vm.Load(service);
return View(vm);
My intention is that the user selects 25, 50, or 100 from the dropdown and a corresponding number of rows is displayed. My understanding is that the Html.DropDownListFor should bind to the SelectedPageOption property, which I would then use in the ViewModel to load the correct number of rows.
However, the change in dropdown value has no effect on the SelectedPageOption property, so the page is reloaded always with the original default '25' rows - taken from the value that is set in the controller. I have tried making SelectedPageOption an Int, having seen examples on the web. I hadn't wanted to do this originally because the SelectedListItem Values have to be strings. It makes no difference. I also tried not using a singleton pattern for the viewmodel - also no effect.
The binding is not completely ineffective. Whatever default value I set in the controller, this is the value that appears in the dropdown. But the binding does not work the other way. If anyone can cast some light on what's going on, I'd appreciate it.
EDIT: What I didn't originally point out, and what turned out to be relevant, is that my controller method containing the above code is asynchronous.
I finally worked out what was going on. Because my controller Index method is asynchronous, I need to await the model update before reloading my viewmodel. It seems obvious now!
SymbolViewModel vm = SymbolViewModel.Instance;
await TryUpdateModelAsync(vm);

Select2 Asp.net MVC - Dropdownlist is not valued with initial data

I am using a select2 using MVC 5 and C#.
I'm having trouble with the dropdownlist (select2) loading with initial data of the model.
The items passed in the corresponding binding field properly valued, but they are not shown in select2!
I mean, despite the list of the ViewModel field correctly valued by the controller, the dropdownlist (select2) is not valued correctly, as if the binding model did not work.
Needless to say, I'm googling for 1,5 days.
Fortunately (:)) I have no problem at the loading of select2 with all items, the dropdownlist works correctly even on the post, even I can take the selected items.
Many Thanks to all
P.s: Now that I'm writing, I have a doubt; Could be that select2 doesn't work with List ?
View
#section scripts{
...
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
}
#Html.DropDownListFor(model => model.MezziStraSelect, Model.MezziStraOrdinari, new { style = "width: 100%", #class = "form-control" })
JS
$(document).ready(function () {
//...
$("#MezziStraSelect").select2({
placeholder: "Select one or more items",
multiple: true,
allowClear: true
});
#if ( Model.MezziStraSelect == null)
{
<text>$("#MezziStraSelect").val(null).trigger("change");</text>
}
}
ViewModel
public Guid[] MezziStraSelect { get; set; }
public MultiSelectList MezziStraOrdinari { get; set; }
Controller
//Load List MezziStraOrdinari
var _stra = m.GetMezziStraordinari().Select(x => new
{
id = x.VoceSpesaID,
desc = x.VoceSpesa
}).ToList();
//view model set field
vm.MezziStraOrdinari = new MultiSelectList(_stra, "id", "desc");
//Load array Mezzi used from item selected
List<Guid> _mezziStraUsati = new List<Guid>();
var elems = dc.ItemSelected.FirstOrDefault(x => x.ItemID.ToString() == _guidSelected);
if (elems!=null)
{
elems.VociSpese.ToList().ForEach(x =>
{
if (x.VociSpesa.Straordinario == true)
_mezziStraUsati.Add(x.VoceSpesaViaggioID); //VoceSpesaViaggioID is GUID
});
if (_mezziStraUsati.Count>0)
vm.MezziStraSelect = _mezziStraUsati.ToArray(); //Guid[]
}
The initial loading of the Select2 unfortunately the binding cannot set the initial values!
So reading the Select2 documentation to this link , I had to proceed with a manual upload via JS.
Practically to try to do an human thing (I hope it is), I created an Extension method in the backend of the Model field
Extension Method
public static string ToSelect2Array<T>(this T[] values)
{
var resp = string.Empty;
values.ToList().ForEach(x => resp += $"'{x.ToString()}',");
if (resp.Length > 0)
resp = resp.Substring(0, resp.Length - 1);
return resp;
}
and then in JS client side, I call it like this:
VIEW (script JS)
#if ( Model.MezziStraSelect != null)
{
<text>
$("#MezziStraSelect").val([#Html.Raw(Model.MezziStraSelect.ToSelect2Array())]);
$("#MezziStraSelect").trigger('change');
</text>
}
else
{
<text>$("#MezziStraSelect").val(null).trigger("change");</text>
}
This is working quite well, but is it possible that there is no way to get it to bind automatically?
I would be curious to know other solutions, more elegant than this I would be grateful for!

How to set string value in model using a dropdown?

I'm working with an ASP.NET mvc projekt and I'm familiar with the usual razor helpers #Html.TextBoxFor... etc. but I'm in the situation where I need to set a string value in the model using a dropdown list, the list always has the same twelve items in it and I just need to populate this list with those items and make sure it sets the field value in the model to the selected one.
I'm curious how I should go about doing this? I've looked at dropdown tutorials and I might be able to get a dropdown working but I'm not sure how to set the field value and I'm not sure where to store these twelve strings. I thought about hardcoding them instead of putting them in a db or something since it's so few but I'm open to better suggestions.
Any help is appreciated
UPDATE
This is my Razor code, I created a simple viewmodel which contains the list of items to display in the dropdown and including the model class I wanna use for this create view.
#Html.DropDownListFor(x => x.question.QuestionId, new SelectList(Model.AreasList), new { #class = "dropdown" })
This is my viewmodel
public class CreateQuestionViewModel
{
public Question question { get; set; }
public IEnumerable<String> AreasList = new List<String> { "Option 1", "Option 2" };
}
It works but I can't figure out why visual studio keeps throwing me a null reference and points at my razor code for the dropdown?
sure, so you need to set the model field based on the selected List Item when the user selects it, assuming that you have a static dropdown list:
//this is your view View1.chtml
#model Class1
<select id="list1" name="list1">
<option value="0">option1</option>
<option value="1">option2</option>
</select>
<script>
$(document.ready)(function(){
//set the list from model
var modelvalue = '#Html.Raw(Json.Encode(Model.ValueFromList))';
$(#list1).val(modelvalue);
});
//handle the change event of Dropdown list
$("#country").change(function()
{
var _selected = $("#list1").val();
var options =
{
type: "POST",
url: '#Url.Action("Action1","controller1")',
data: _selected + ,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
//set the returned value as the selected dropdownlist value
$(#list1).val(msg);
}
}
};
.ajax(options);
</script>
//this is the class that you want to set the value in (the Model)
Class1
{
public string ValueFromList {get;set;}
}
//then you need an action method ( in your Controller) that will update the Model with the new Value:
public Controller1
{
[HttpPost]
public JsonResult Action1(string value)
{
Class1 cl1=new Class1();
cl1.ValueFromList=value;
return Json(new {Success="true", cl1});
}

Dropdownlist in MVC 4

I am trying to use simple dropdownlist in my edit form, where user can correct information, with help of dropdownlist.
So I use this:
public ActionResult Edit(string zonesList)
{
using (var dbVn = new userDbEntities())
{
...
var zList = new List<string>();
var zQuery = from d in dbVn.TimeZoneTables // take data for List from table
select d.TimeZone;
zoneList.AddRange(zQuery.Distinct());
ViewBag.zonesList = new SelectList(zList);
}
}
And in View I put this code:
Zones: #Html.DropDownList("zonesList")
My question is, how in View use this:
#Html.DropDownList("zonesList")
on this code
#Html.EditorFor(model => model.TimeZoneId)
Thanks for any idea.
Use jquery or javascript as below:
#Html.DropDownList("zonelist", new SelectList(ViewBag.zonesList,<value>,<text>),"Select Vendor/customer",new{ #class = "form-control",required = "required",#id="zone" })
Now want to change editor for value
#Html.EditorFor(model=>model.TimezoneId,new{#id="time"})
Jquery code for above
<script type="text/JavaScript">
$(document).ready(function () {
$("#zone").change(function(){
var t =$("#zone").val();
if(t==/*somevalue*/)
{
//set value for time id
//like $("#time").val(/*new val*/)
}
});
});
</script>
As I am using Time Zones I find cool solution that works only for time zones. First I actualy don't need table with time zones saved, but simple in my View I call library of .Net timezones:
#Html.DropDownListFor(o =>o.TimeZoneId, TimeZoneInfo.GetSystemTimeZones().Select(o => new SelectListItem{Text = o.DisplayName, Value = o.Id}))

Two issues with field validation

I am working on my first ASP.NET MVC 3 project. For some of the fields on an edit page I want the user to be able to either choose a value from previously-entered values or enter a new one, so I'm using the jQuery autocomplete to accomplish this. That part seems to work just fine. Now, for some fields the user can choose to enter a value or not and if they do enter one, I want to validate it against some rules, so I created my own ValidationAttribute.
The validation piece will definitely check the given value against the rules and return the correct boolean value for the IsValid call. Great.
The first problem that I'm having is that if my validator's IsValid returns false, it displays the error message I've specified but if I enter something which is valid, the TextBox clears it's error background color but the error message does not clear. This happens in either FF or IE8.
The second problem is that for FireFox, my autocomplete values will display again when I edit the text in the textbox but in IE 8, once the error condition exists, my autocomplete stops working. Occasionally, if I enter a value which I know is in the autocomplete list, it will show up but it seems a bit flaky.
I may just be doing this validation thing wrong. Here's the relevant code I use. I'd be quite interested in any guidance one can give about either of these issues. The attribute is a test one but it exhibits the behavior on my page.
My ValidationAttribute:
public class MyAttribute : ValidationAttribute
{
...
public override bool IsValid(object value)
{
if (value == null)
{
return true;
}
var stringValue = Convert.ToString(value);
if (stringValue.Length == 0)
{
return true;
}
if (stringValue.Trim().Length == 0)
{
return false;
}
return true;
}
...
}
My autocomplete code:
$("#toppingid").autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("AvailableToppings", "IceCream")', type: "POST", dataType: "json",
data: { query: request.term },
success: function (data) {
response($.map(data, function (item) {
return { label: item, value: item };
}))
}
})
},
minLength: 1
});
My controller action:
public JsonResult AvailableToppings()
{
// I actually retrieve this differently, but you get the idea
List<string> all = new List<string>() { "BerryCrush", "Caramel", "Fudge" };
return Json(all, JsonRequestBehavior.AllowGet);
}
My view snippet:
#Html.TextBoxFor(model => model.Topping, new { #id = "toppingid" })
#Html.ValidationMessageFor(model => model.Topping)
My viewmodel snippet:
[DisplayName("Topping:")]
[MyAttribute(ErrorMessage = "Can't be all blanks!")]
public string Topping { get; set; }
In my post action, I have logic something like this:
[HttpPost]
public ActionResult Create(IceCreamCreateEditViewModel viewModel)
{
if (ModelState.IsValid)
{
// stuff happens here which isn't germane
return RedirectToAction("Index");
}
// redisplay the view to the user
return Create();
}
I think that's all the relevant pieces of code. Thanks for any guidance you can provide.
Concerning your first question, it looks like the autocomplete plugin removes the input-validation-error class from the textbox when a selection is made. Because of this the textbox clears its background. One way to workaround this is to subscribe for the select event and reapply this class if there is an error (by checking whether the error label is displayed):
$("#toppingid").autocomplete({
source: function (request, response) {
...
},
select: function (event, ui) {
var topping = $('#toppingid');
// find the corresponding error label
var errorLabel = $('span[data-valmsg-for="' + topping.attr('name') + '"]');
if (errorLabel.is(':visible')) {
// if the error label is visible reapply the CSS class
// to the textbox
topping.addClass('input-validation-error');
}
},
minLength: 1
});
As far as your second question is concerned, unfortunately I am unable to reproduce it. The autocomplete doesn't stop working in IE8 if there is a validation error.

Resources