Changing current viewModel in .NET MVC application - javascript

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?

Related

Trying to post a list collection to the controller with ajax

I'm trying to post a list collection to the controller with a full page post back to the server. The data from the client side is written with JavaScript / jQuery and the server code is written in C# using ASP.Net MVC.
I'm not sure what the issue is because when the ItemCheck method is hit with a breakpoint on the first curly brace after the method name but the model object Items property is null even though it's in the form data mentioned further below.
The code below is simplified for ease and is not working.
Input hidden field in the view where the JavaScript adds an item to it each time add button is pressed.
#model UI.ViewModels.ItemResource
#Html.HiddenFor(model => model.Items, new { #id = "Items" })
<button class="btn-default btn" id="AddItem" name="AddItem" type="button" disabled>Add</button>
JavaScript
var items = [];
// This code only adds an item to the items collection input hidden
// field for a full page post back to the server.
var addItemToList = function () {
var item = {
ItemDate: $(date).val(),
ItemAmount: $(amount).val()
};
items.push(item);
$("#Items").val( JSON.stringify(items));
};
Controller
public ActionResult ItemCheck(ItemViewModel model)
{
if (result.IsValid)
{
model.Items = _anotherViewModel.Items;
_anotherViewModel.Items= null;
model.IsValid = _itemService.Save(model, _Itemhelper.GetUserId());
}
else
{
//Validation here
}
return View(model);
}
ViewModels
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace UI.ViewModels.ItemResource
{
public class ItemsViewModel
{
public ItemsViewModel()
{
Items = new List<ItemViewModel>();
}
[JsonBindable]
public List<ItemViewModel> Items { get; set; }
}
public class ItemViewModel
{
public DateTime ItemDate { get; set; }
public decimal ItemAmount { get; set; }
}
}
FormData
Items: [{"ItemDate":"2020-06-05","ItemAmount":"2267"}]

ListBoxFor add data attribute to each option element

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.

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))

Is there any way to call JavaScript in an MVC4 ActionLink for one of the RouteValue parameters?

I have a drop down list (DropDownListFor) and an ActionLink on my page. Basically, the problem I'm having is I'm trying to capture the selected value from my drop down list and passing that into my ActionLink as an ID. Here's my code:
#Html.DropDownListFor(x => x.Capsules, new SelectList(Model.Capsules, "pk", "name", "pk"))
<br />
#Html.ActionLink("Submit", "Create",
new { controller = "Process", id = /*JavaScript here to get the selected ID for the DropDownList above*/ },
new { data_role = "button" })
For what I'm trying to accomplish, is there a way to embed JavaScript into my Html.ActionLink call? If there's not a way, or if it's not recommended, could you please advise of another solution to solve this problem? Thanks in advance!
You can do this via intercepting the link using javascript Darin has posted an example of this.
However, it looks like you're trying to submit some values using an ActionLink, and you're probably better off creating a viewmodel which holds all the values you want, and then posting everything using a submit button. This allows you to post more data than just the ID, prevents you from being dependent on Javascript, and keeps all of the code server side instead of mixing and matching.
Judging by the small code you've posted - you already have a model, probably some strongly typed entity, and it has a property called Capsules.
In your controller, create the view model which holds the view's data:
public class YourViewModel
{
YourModel YourModel { get; set; }
public int CapsuleId { get; set; }
}
Then your view:
#using( #Html.BeginForm( "Create", "Process" ) )
{
#Html.DropDownListFor(m=> m.CapsuleId, new SelectList(Model.YourModel.Capsules, "pk", "name", "pk"))
<input type="submit">
}
Then your controller action to handle this:
[HttpPost]
public ActionResult Create( YourViewModel model )
{
var id = model.CapsuleId;
// do what you're going to do with the id
return View();
}
You can put dummy value for the id parameter like this :
#Html.ActionLink("Submit", "Create",
new { controller = "Process", id = "dummy" },
new { data_role = "button" })
Then replace that value when the link is clicked.
// Assuming your link's id is `submit`, and the dropdown's id is `capsules`
$('#submit').click(function() {
var id = $('capsules').val();
$(this).href = $(this).href.replace('dummy', id);
});

Dynamic created checkbox using foreach in asp.net mvc

I have list page to show all images with its name from database in asp.net mvc list action (PhotoList - get).. in that view page (PhotoList.aspx), I have created checkbox to delete multiple rows. I want scenario like following
First page shows the list with in first column checkbox and in second column PhotoName and on the down page one button for delete selected rows .
when selects checkboxes and clicks the delete button, according to selection the rows will be deleted from database and return the same list page..
I don't understand where to write code for delete and how?
<% foreach (var item in Model) { %>
<tr>
<td>
<input type="checkbox" name="deleteImage" value="<%= item.PhotoId %>"/>
</td>
<td>
<%= Html.ActionLink("Edit", "Edit", new { id=item.PhotoId }) %>
</td>
<td>
<%= Html.Encode(item.PhotoName) %>
</td>
</tr>
<% } %>
<input type="button" name="Delete" value="Delete Selected items"/>
The Code for delete will be written in the HttpPost action for delete. Something like below should work if you are using myModel
[HttpPost]
public ActionResult Delete(myModel deleteEntries) //This is the post-version of your Action that rendered the view..If it's Edit, then change the name to Edit
{
var deleteList = db.deleteEntries.where(d => d.checkBox == true).ToList();
foreach (myList my in deleteList)
{
db.myList.Remove(my); // remember db should be your DbContext instace
}
db.SaveChanges();
}
UPDATE
You will first need to make a ViewModel because otherwise you cannot recognize which entries are checked for deletion with the help of checkbox.
Make a ViewMode class like following
using pratice3.Models;
public class MyPhotoViewModel
{
public UserManagementDbEntities.tblPhoto TablePhoto { get; set; }
public bool checkBox { get; set; }
}
Return this to your view
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult PhotosList()
{
var viewModel = _datamodel.tblPhoto.Select(g => new MyPhotoViewModel
{
TablePhoto = g;
checkBox = false;
}).ToList();
return View(viewModel);
}
In View, change the using statement to reflect IEnumerable<MyPhotoViewModel> and make appropriate changes accordingly.
Then, define your Post Action like following
[HttpPost]
public ActionResult PhotosList(IEnumerable<MyPhotoViewModel> myPhotoList)
{
var deleteList = myPhotoList.where(d => d.checkBox == true).ToList();
foreach (var deletePhoto in deleteList)
{
_datamodel.tblPhoto.DeleteObject(deletePhoto.TablePhoto);
}
db.SaveChanges();
}
Using jQuery you can do this.
On button click get all the Ids of photos, something like this
var selected = new Array();
$('name="deleteImage" input:checked').each(function () {
selected.push($(this).attr('id')));
});
var selectedIds = selected.join(',');
Now on button click, make ajax call to some function on server side which will accept these ids and will delete from DB or so.
$.ajax({
url: '#Url.Action("DeleteRecord", "UserManage")',
data: 'ids=' + selectedIds + '&time=' + new Date(), //Date makes each call unique
success: function (data) {
//You can reload page
},
error: function (data) {
//You can show error
}
});
Hope this helps.

Categories