ListBoxFor add data attribute to each option element - javascript

I have a MultiSelectList that I am currently using to create a ListBoxFor in my view. On my ViewModel I have an additional property on each of the items in the list that I would like to expose in the HTML for client side manipulation.
I have a checkbox above this list. When a user clicks the checkbox only data-x="true" items should show in this list. If the user does not click the checkbox, all items are shown (data-x="true" and data-x="false"). This logic is done client side each time the checkbox it changed
I am assuming the best way to do this would be to add a data-* attribute to each of the option elements. How exactly would I go about doing this? I am thinking an HTMLHelper method would be needed to extend the functionality of ListBoxfor but I am not sure where to get started, or if this is even the best way to go about this?

To be able to generate <option> elements with a data=* attribute, you would need to create you own class based on SelectListItem with additional properties for the attributes, and then generate you own HtmlHelper extension method based on the code in the System.Web.Mvc.SelectExtensions class.
A far easier way to handle this would be to pass collection you use to build the SelectList to the view, assign it to a javascript array and then use javascript/jquery to handle the checkbox .click() event and rebuild the list of options in the <select> element. In your case, it could simply be a case of hiding/showing items based on the value of the checkbox.
For example, if you have a view to select a product, and include a checkbox to limit that selection to only locally made products, your models might be
public class MyViewModel
{
public bool UseLocalProductOnly { get; set }
public int SelectedProduct{ get; set; }
public IEnumerable<SelectListItem> ProductList { get; set; }
public IEnumerable<int> LocalProducts { get; set; }
}
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public bool IsLocalProduct { get; set; }
}
and in the controller
var products = db.Products;
MyViewModel model = new MyViewModel()
{
ProductList = new SelectList(products, "ID", "Name"),
LocalProducts = products.Where(x => x.IsLocalProduct).Select(x => x.ID)
}
return View(model);
and in the view
#Html.CheckBoxFor(m => m.UseLocalProductOnly)
#Html.DropDownListFor(m => m.SelectedProduct, Model.ProductList)
<script>
var localProducts = #Html.Raw(Json.Encode(Model.LocalProducts))
var select = $('#SelectedProduct');
var options = select.children('option');
$('#UseLocalProductOnly').click(function() {
if ($(this).is(':checked')) {
// reset the selected option if it would otherwise be hidden
if ($.inArray(Number(select.val()), localProducts) === -1) {
select.val(localProducts[0]);
}
// hide options that are not local products
$.each(options, function () {
if ($.inArray(Number($(this).val()), localProducts) === -1) {
$(this).hide();
}
});
} else {
// show all options
productOptions.show();
}
});
</script>
Alternatively you could use .prop('disabled', true); (or false) to enable or disable options rather that hiding them.

Related

Order dropdown list in ASP.Net mvc 5 application

I have a dropdown and I want it to appear in a particular order where dropdown option header should come before footer. but I am not able to do so.
Helper
public static readonly string HEADER_ID = "-1000";
public static readonly string FOOTER_ID = "-1001";
CSHTML
<select id="simTextEditorSelection" onchange="ShowTextEditorBasedOnSelection();" style="float:right;">
#foreach (PageInfoMV anItemForEditor in Model.ItemContents)
{
<option value="#anItemForEditor.ItemId">#anItemForEditor.ItemDisplayText</option>
}
UI
P.S: I don't want to change the enum values of Header and footer. Please guide me.
My Attempt:
#foreach (PageInfoMV anItemForEditor in Model.ItemContents.OrderByDescending(x=>x.Id))
But it created some other issues. So, I want to avoid it.
Assume you have this class:
public class MyClass
{
public int Id { get; set; }
public int Name { get; set; }
}
In the Action you can create a SelectList from any list as followed:
public ActionResult Create()
{
var list = db.MyClass.ToList(); //or an other way to get the list of items
//you can add som more items to the list:
list.Add(new MyClass { Id=-1000, Name="Some Name" });
ViewBag.Selectlist = new SelectList(list.OrderByDescending(x=>x.Id), "Id", "Name");
return View();
}
In the View:
#{
var optionList = ViewBag.Selectlist as SelectList;
}
#Html.DropDownListFor(model => model.someProperty, optionlist, "- Select an option -")
Change your cshtml to this and you should have your wish
<select id="simTextEditorSelection" onchange="ShowTextEditorBasedOnSelection();" style="float:right;">
#foreach (PageInfoMV anItemForEditor in Model.ItemContents.OrderByDescending())
{
<option value="#anItemForEditor.ItemId">#anItemForEditor.ItemDisplayText</option>
}

How to load a multi select (which is linked to a model) dynamically in mvc, using ajax

Can someone kindly let me know how can we pass on a argument from the view to controller, which loads the model.
In the below model, TaskNames gets loaded in a multi select box and MonthEnd gets loaded in a drop down box.
Model
public class TaskAssignModel
{
public List<string> TaskNames { get; set; }
public List<Task> Tasks { get; set; }
public List<MonthEndObj> MonthEnd;
}
Whenever i change the MonthEnd dropdown box ,Tasknames should be loaded based on the value selected in the MonthEnd dropdown.
How is this achievable ? Would like to know if there is a way to get this done through ajax.
***Controller****
public ActionResult AssignMonthEnd()
{
TaskAssignModel tm = new TaskAssignModel();
DataAccess DA = new DataAccess();
tm.Tasks = new List<Task>();
tm.Tasks = DA.getTasks();
tm.MonthEnd = DA.getActiveMonthEnd();
return View(tm);
}
View
#Html.ListBoxFor(m => m.TaskNames, new MultiSelectList(#Model.Tasks, "TaskID", "TaskName", #Model.TaskNames), new { style = "height:200px; width:400px;overflow-x: scroll", size="5"})
#Html.DropDownListFor(m => m.MonthEnd, new SelectList(Model.MonthEnd,"ActiveMonthEnd","ActiveMonthEnd",0))

Changing current viewModel in .NET MVC application

My View uses the Model like below:
public class ObjectViewModel
{
public int ChosenVariant{ get; set; }
public List<Object> Objects{ get; set; }
}
but on page I am displaying details only of one of Object from the list (whose id is equal ChosenVariant).
On the same page I have radio buttons and each of them is binded to one of the Objects from the list:
#foreach (var obj in Model.Objects)
{
<div class="radio">
#{
var options = new RouteValueDictionary();
options["onchange"] = "UpdatePage()";
if (product.ID == Model.ChosenVariant)
{
options["checked"] = "checked";
}
}
#Html.RadioButtonFor(p => Model.ChosenVariant, #product.ID, options)
</div>
}
My problem is that how I can refresh the Model.ChosenVariant and render once again page without refresh?
My first idea was returning whole Model with new value of Model.ChosenVariant in javascript function (on onchange radio button).
This function will call Post action to a Controler, which return once again whole Model (but with new changed Model.ChosenVariant. Then on done action of this Post call I will use $(panel).html(data); for refresh the page.
Is there any easier way to change the current viewmodel without calling Controller?

Return a Javascript array to action

Here's my problem:
i have a JS array that i want to pass it to an action and then render that action's View.
this is my array and i fill it Using Jquery like so :
var factorlist = [];
factorlist.push({ ID: data.ID, Name: data.Name, number: data.number, SingelPrice: data.SingelPrice, TotalPrice: data.TotalPrice })
(data come from an AJAX Call)
then i put a hidden input element in my page to put my array in it and send it with a submit.
here is hidden input and submit button :
<input type="submit" id="input" name="input" />
<input type="hidden" id="list" name="list"/>
This is how i send it :
$('form').submit(function (event) {
$('#list').val(JSON.stringify(factorlist));
});
and this is the action that i'm sending the array to :
public ActionResult PrePayment(List<Order> list)
{
return View(list);
}
and my order class :
public class Order
{
public int ID { get; set; }
public string Name { get; set; }
public int number { get; set; }
public float SingelPrice { get; set; }
public float TotalPrice { get; set; }
}
**Now the thing is i get and empty list in action not null...what is the problem and is there any other way to do this? **
The default MVC data binding will not work for you in this case, you have to deserialize your values manually:
var js = new JavaScriptSerializer();
list = (Order[])js.Deserialize(Request.Form["list"], typeof(Order[]));
To avoid doing this every time you can register a Custom Model Binding for that type too, check an example in http://www.codeproject.com/Articles/605595/ASP-NET-MVC-Custom-Model-Binder
You should use Json instead of JS array. More details http://msdn.microsoft.com/en-us/library/system.web.mvc.jsonresult(v=vs.118).aspx
if i understand you right, you want to post your js array from form to controller action, so basing on this article there is a solution:
$('form').submit(function (event) {
$(factorlist).each(function (i, el) {
$('form').append($('<input />', {
type: 'hidden',
name: 'list[' + i + '].ID',
value: el.ID
}));
// and so on for each your of objects property
});
});
More correct way is to do it using ajax and redirect on success callback.

Find ids of checked checkboxes with jQuery in MVC

I have a Field model, which represents a certain field (Name, Description, ...)
class FieldModel : EntityModel
{
...
public bool ToCopy { get; private set; }
public string Id {get; private set; }
...
}
An Index model, which has a collection of Fields:
class EntityModel
{
...
}
class IndexModel
{
public IEnumerable<EntityModel> Fields { get; private set; }
}
Controller for copy, that should accept ids of fields to copy:
public void CopyFields(string[] fieldsIds)
{
...
}
And I need to select certain fields to copy by checkboxes. So in the vew for Field I added
#Html.CheckBoxFor(x => x.IsSelectedForCopy)
In the view for Index
<button onclick="onCopyClick('#Model');" type="button" class="btn showButton">Copy Fields</button>
And now I need to write a script to select all checked fields and send their Ids to the controller. I have zero experience with Javascript/jQuery, so could someone help me with that?
This should get you started at least ;)
You give jQuery some css selectors and it gives you the objects that match...
$("input :checked").each(function() {
alert($(this).attr("id"));
});
Depending on how you want to send them, you could then append each id to a hidden field on a form like so:
$("input :checked").each(function() {
var tmp = $("#myHiddenField").val();
tmp += " " + $(this).attr("id"));
$("#myHiddenField").val(tmp);
});
$.ajax("TheURLToPostTheDataTo",
{data: [
{idsToSend:$("#myHiddenField").val()}
],
success: function() {
alert("Done");
}
});
Then submit, and on the serverside trim and split by space?

Categories