There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'print_ad_option_id' - ajax

So I have method in which I do some ajax:
function prodChange() {
console.log(this.value);
// ajax
var url = '#Url.Action("GetAdvProdList", "Contract")' + '?prod_id=' + this.value;
$.ajax({
url: url,
type: 'GET',
success: showAdvProd,
error: function() {
console.log("FAILSHAKUREHKGAHH");
}
});
}
The ajax returns successfully and calls this controller method.
public ActionResult GetAdvProdList(int prod_id) { // product id
// get advertising products for this product
OutlookMediaEntities1 db = new OutlookMediaEntities1();
var advsList = from printAdOption in db.print_ad_option
where printAdOption.print_product_id == prod_id
select printAdOption;
List<SelectListItem> adv_list = new List<SelectListItem>(); // list of ads
List<print_ad_option> advs = advsList.ToList(); // list from db
foreach (print_ad_option av in advs)
{
SelectListItem temp_item = new SelectListItem();
temp_item.Text = av.name;
temp_item.Value = av.print_ad_option_id.ToString();
adv_list.Add(temp_item);
}
ViewData["advproducts"] = new SelectList((IEnumerable<SelectListItem>)adv_list.ToList(), "Value", "Text");
return null;
}
I'm returning null because it doesn't work if I return View or PartialView, and I don't think I want it to return those things anyway. All I want is the viewdata stuff to be set.
The ajax worked well before I added code to use the view data. Unfortunately when I try to use the new ViewData in the ajax success method, I get this error:
"There is no ViewData item of type 'IEnumerable' that has the key 'print_ad_option_id'"
The thing is that I get this error when I first load the page, so it seems to be attempting to evaluate the "#Html.DropDownListFor..." before the showAdvProd function is called:
// called when the ajax returns a list of adv prods in a viewdata
function showAdvProd() {
// add drop down
$("#drdn1").append('#Html.DropDownListFor(m => m.print_ad_option_id, ViewData["advproducts"] as SelectList)');
}
The function that does ajax is called when an item is selected from a (different) dropdown menu, but with this error the page doesn't even load, so obviously the ajax function is never called and thus the controller method never called. So of course it won't recognize the viewdata...
I'm similarly creating a dropdown menu in another part of my form, using viewdata but without ajax, and it works fine. So I think something is wrong with my ajax or my controller method, not with how I'm using the viewdata.
Thank you in advance for any help!

The problem is that on your initial page load, the view engine will evaluate all the code blocks - anything with a '#' symbol in front of it. Thus it will try and look for a ViewData item called advproducts before it exists, even though that reference is within a javascript function that hasn't been called yet. Remember - code blocks (such as #Html.blahblahblah() are evaluated server side, while you are expecting your ajax to run on the client side, after the page has been sent to the client.
A couple of options: Returning a partial view should work. You could return a partialview that contains a dropdown and fill it from the ViewBag. That would look like this:
initial page:
...
<div id="advProductsSection"></div>
...
Your ajax would call the same function, but would return a partial view:
public ActionResult GetAdvProdList(int prod_id) { // product id
...
ViewData["advproducts"] = new SelectList((IEnumerable<SelectListItem>)adv_list.ToList(), "Value", "Text");
return View("_AdvProducts");
}
And then a partial view (Here named _AdvProducts.cshtml):
#Html.DropDownList("className", (IEnumerable<SelectListItem>) ViewBag["advproducts"])
Your ajax function would need to change to replace the div with the new partial:
success: function (result) {
$('#advProductsSection').html(result);
}
Or something like that..
A second alternative is to return JSON from the Action Method and populate a dropdown with that.
Your Controller:
...
return JSON(adv_list.ToList());
}
Then in your ajax success func:
success: function(list) {
// states is your JSON array
var $dropdown = $('#Dropdown');
$.each(list, function(i, product) {
$('<option>', {
value: list.Value
}).html(list.Text).appendTo($dropdown);
});
}
You'd need to cleat the dropdown again when prodchange is called.

Related

How To Correctly Use the HTML.DropDownList with Ajax Calls for MVC

I populated a SelectList Programmatically using the SelectList Constructor (IEnumerable, String, String)
IEnumerable<Permission> ie_SelLstContentAvailPerms;
tmpLstPermissions = FilterAssignablePermissionsByRoleMgblty(p_iRoleId,vmRolePermAdmin.lstPermissionsSource);
//test Forcing Results in to IEnumerable format for Select list Constructor
ie_SelLstContentAvailPerms = tmpLstPermissions.ToList();
vmRolePermAdmin.selLstPermissionsSource = new SelectList(ie_SelLstContentAvailPerms, "PermissionId", "Name");
And I use the DropDownList structure :
#Html.DropDownList("ddlAssignedRolePermissions", (Model.selLstCurrentRolePermissions), null, new { #id = "ddlAssignedRolePermissions", #size = "5", #onchange = "ddlAssignedRolePermissionsEvent(this)" })
My previous use of this structure has an ajax call who's success method is returning the updated model ----but its main body(Postify to AssignPermission(iUserID))is doing the work to the viewmodel based upon the item selected in the drop down list
$.ajax({
url: "~/../../User/AssignPermission",
type: "POST",
data: $.postify({ "p_permId": optionSelectedPerm.value, "p_UserId": iUserId }),
cache: false,
success: function () {
ReloadUserPermissions();
},
error: function () {
// alert("FAIL"); //TODO ?
}
});
I was attempting to replicate this structure for a new page , but instead of using the success results method of the Ajax call I've been trying to return the updated model in the main ajax work.. if the above example were structured this way there would be no success function and the controller ActionResult method would return the updated model. This isnt working . I see the data (updated) in the view while debugging but it does not up date the view ...
Do I have to use the success function of the Ajax call in order to update the view?
<script type="text/javascript">
$(document).ready(function () {
var optionSelectedPerm;
var mvcTmpData_iCurrentRoleID;
});
function SelectedRole(p_lstRole) {
debugger;
mvcTmpData_iCurrentRoleID = $("#ddlSelectedRole").val();
$.ajax({
url: "~/../../AdminRoles/AdminRolePermissions",
type: "POST",
data: $.postify({ "p_nullRoleId": mvcTmpData_iCurrentRoleID }),
cache: false,
success: function () {
AjaxReloadRolePermissions();
},
error: function () {
},
});
function AjaxReloadRolePermissions() {
//alert("Current RoleID: " + mvcTmpData_iCurrentRoleID);
var url = '#Url.Action("ReloadRolePermissions", "AdminRoles", new { p_RoleId = "zReplaceRoleId" })';
window.location.href = url.replace('zReplaceRoleId', mvcTmpData_iCurrentRoleID);
}
}
</script>
Please note that in order to accomplish the first working scenario the controller method as cited in the Ajax call "AssignPermission" is an ActionResult of Type EmptyResult and marked [HttpPost] so basically it can do work and not worry about a real return. BUT !! the Success function of this same Ajax call allows me to update the view with the newly adjusted ViewModel....
My atempt to reproduce my original results is failing I see the model content but it doesnt render in the view
If anyone cares its pretty simple the Ajax function's main work cant call a controller action that updates the view. However the Ajax success call can assuredly call one of the controller's ActionResults to update the view and thereafter its related Partials in that view ,,,
the controller action in tha main part of the ajax call that DOES WORK needs to be marked EmptyResult & [HttpPost]
The controller action that really fires up an ActionResult to update your view ,, in my case, just returns the view and the newly modified model... and again note its called by the Success function of the previous cited ajax function The last code posting above pretty much covers it all

Is there a way to use AJAX on a DropDownList changed event to dynamically modify a partial view on a page?

Is there a way to use AJAX on a DropDownList changed event to dynamically modify a partial view on a page?
My main page has a DropDownList (DropDownListFor) and a partial view which ONLY contains a list of "items". The items shown in this partial view are dependent upon the item selected in the DropDownList. There's a 1 to many relationship between the DropDownList item and the items in the partial view. So, when the user changes the value of the DropDownList, the content in the partial view will dynamically change to reflect the item selected in the DropDownList.
Here's my DropDownList:
<div data-role="fieldcontain">
Choose Capsule:<br />
#Html.DropDownListFor(x => x.CapsuleFK, new SelectList(Model.Capsules, "pk", "name", "pk"), new { id = "ddlCapsules" })
<br />
</div>
Here's my Partial View declaration on the same page:
<div data-role="fieldcontain">
#Html.Partial("_FillerPartial", Model.Fillers)
</div>
I'm not very familiar with Ajax, but looking at other examples, here's what I have for my Ajax:
$(document).ready(function () {
$('#ddlCapsules').change(function () {
// make ajax call to modify the filler list partial view
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
alert("server returned: " + data);
}
});
});
});
And finally, here's a screenshot of what's going on. By changing the "Choose Capsule" drop down list, I want the Filler list to update dynamically:
You can load the drop down list as a partial view from the controller using ajax.
The controller code:
[HttpGet]
public virtual ActionResult GetFillersByCapsule(string cappk)
{
var model = //Method to get capsules by pk, this returns a ViewModel that is used to render the filtered list.
return PartialView("PartialViewName", model);
}
The main view html:
<div id="filteredList">
</div >
The partial view
#model IEnumerable<MyCapsuleModel>
foreach (var x in Model)
{
//Render the appropriate filtered list html.
}
And you can load the filtered list using ajax:
$('#ddlCapsules').change(function () {
// make ajax call to modify the filler list partial view
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
$("#filteredList").empty();
$("#filteredList").html(data);
}
});
});
Hope this helps.
You can't update the partial, per se, because the partial will never be rendered again without a page reload. Once you receive the HTML, ASP is done, you're on your own at that point.
What you can do, of course, is switch out the content of a particular div or whatever using JavaScript. Your example in particular screams Knockout, so that's what I would recommend using.
Change your HTML to add a data-bind to your containing div:
<div data-role="fieldcontain" data-bind="foreach: filler">
<button data-bind="text: name"></button>
</div>
And your DropDownList:
#Html.DropDownListFor(x => x.CapsuleFK, new SelectList(Model.Capsules, "pk", "name", "pk"), new { id = "ddlCapsules", data_bind = "event: { change: updateFillers }" })
Then, some JavaScript:
var FillersViewModel = function () {
var self = this;
self.fillers = ko.observableArray([]);
self.updateFillers = function () {
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
self.fillers(data.fillers) // where `fillers` is an array
}
});
}
}
var viewModel = new FillersViewModel();
ko.applyBindings(viewModel);
This is a very simplistic example, and you'll need to do some more work to make it do everything you need it to do in your scenario, but the general idea is that every time the dropdown list is changed, Knockout will call your updateFillers method, which will execute the AJAX and put new data into the fillers observable array. Knockout automatically tracks changes to this array (hence the "observable" part), so an update is automatically triggered to any part of your page that relies on it. In this scenario, that's your div containing the buttons. The foreach binding will repeat the HTML inside for each member of the array. I've used a simple button element here just to illustrate, but you would include the full HTML required to create your particular button like interface. The text binding will drop the content of name in between the opening and closing tag. Refer to: http://knockoutjs.com/documentation/introduction.html for all the binding options you have.
There's much more you could do with this. You could implement templates instead of hard-coding your HTML to be repeated in the foreach. And, you can use your partial view to control the HTML for this template. The important part is that Knockout takes the pain out of generating all this repeating HTML for you, which is why I recommend using it.
Hope that's enough to get you started.

Accessing model data, from MVC3 partial view, in controller without passing it explicitly in the view

I have a MVC3 partial view that is called with a model.
#model SomeModel
The model have an Id parameter.
In the view I call #Html.Action("SomeMethod", "SomeController")
Is there any way to access the Id parameter in the SomeMethod ActionResult without passing it explicitly like this:
#Html.Action("SomeMethod", "SomeController", new {"Id" = Model.Id})
The problem is that I can not change the source code of the partial view. And I need the Id value. The Id is not used in the partial view so I can not access it via JavaScript.
Is the model passed to the HttpContext and is there any way to pass it?
EDIT: The thing is that I am developing a plugin for nopCommerce, like the ones that are offered by nop-templates. nopCommerce is an open source software and I can change the code, but the plugin will be shipped separately, so it is not recommended to make changes in nopCommerce views and the view that I am referring to is such.
When you can't change the sourcecode of the partial view, there is no way of getting to the id value in your controller. Its completely decoupled as thats one major point of the MVC pattern.
You have to explicitely pass it as a parameter to your action.
A dirty workaround might be to store that id somewhere in the Session.
In my project i fill my state drop down list by country id like this
in my view
i pass country id to my controller ActionResult like this
<script type="text/javascript">
function cascadingdropdown() {
var countryID = $('#countryID').val();
$.ajax({
url: "#Url.Content("~/City/State")",
dataType: 'json',
data: { countryId: countryID },
success: function (data) {
alert(data);
$("#stateID").empty();
$("#stateID").append("<option value='0'>--Select State--</option>");
$.each(data, function (index, optiondata) {
alert(optiondata.StateName);
$("#stateID").append("<option value='" + optiondata.ID + "'>" + optiondata.StateName + "</option>");
});
},
error: function () {
alert('Faild To Retrieve states.');
}
});
}
</script>
in my controller i have action
public JsonResult State(int countryId)
{
var stateList = CityRepository.GetList(countryId);
return Json(stateList, JsonRequestBehavior.AllowGet);
}
i think this will help you ....

How to pass the full Model from view to controller via jquery in a MVC c# application

I have a list of checkbox's and textbox's. I want to let the user add items to the list via a partial view modal popup.
After the user adds an item to the list, if any items on the original view have values in them, I want them preserved, and the page refreshed with the added items.
I want to send the full model back to the controller from the original view, I can then just add the new items to that model and pass the model back to the original page and have all my values preserved.
I could grab all the values and pass them via loops and such in javascript (very tedious), but I think the full model would be the easiest way.
I sawe a link from Laviak on a post from here..., but I can't get it to work.
it states....
If you need to send the FULL model to the controller, you first need the model to be available to your javascript code.
In our app, we do this with an extension method:
public static class JsonExtensions
{
public static string ToJson(this Object obj)
{
return new JavaScriptSerializer().Serialize(obj);
}
}
On the view, we use it to render the model:
<script type="javascript">
var model = <%= Model.ToJson() %>
</script>
You can then pass the model variable into your $.ajax call.
Has anyone got this to work???
Thanks
Bill
you can do something like this:
<script type="text/javascript">
var dataViewModel = #Html.Raw(Json.Encode(Model)); //Make sure you send the proper model to your view
function MethodPost(param1, param2, etc...) {
dataviewModel.Param1 = param1; //Or load a value from jQuery
dataviewModel.Param2 = $("#param2").val();
}
//Pass it to a controller method
$.post("#Url.Action(MVC.Home.PostMethodInController())", { viewModel: JSON.stringify(dataViewModel)} , function(data) {
//Do something with the data returned.
}
</script>
In the controller you get your class/model using Json.Net which is available on nuget.
public virtual ActionResult Index()
{
return View(new MyModelToView());//Send at least an empty model
}
[HttpPost]
public virtual JsonResult PostMethodInController(string viewModel)
{
var entity = JsonConvert.DeserializeObject<MyObject>(viewModel);
//Do Something with your entity/class
return Json(entity, JsonRequestBehavior.AllowGet);
}
Hope this helps.

Dynamically load Partial Views

How can i dynamically load a Partial View?
I mean I have this view, lets say ListProducts, there I select some dropdownlists with products, etc, and with the selected values from those I wanna fill a partial view, which would be in a div that was invisible but after onchange() event would become visible and with the data from the specific selected items.
Use jQuery's $.load() with a controller action that returns a partial view.
For example:
HTML
<script type="text/javascript">
$(document).ready(function()
{
$("#yourselect").onchange(function()
{
// Home is your controller, Index is your action name
$("#yourdiv").load("#Url.Action("Index","Home")", { 'id' : '123' },
function (response, status, xhr)
{
if (status == "error")
{
alert("An error occurred while loading the results.");
}
});
});
});
</script>
<div id="yourdiv">
</div>
Controller
public virtual ActionResult Index(string id)
{
var myModel = GetSomeData();
return Partial(myModel);
}
View
#model IEnumerable<YourObjects>
#if (Model == null || Model.Count() == 0)
{
<p>No results found</p>
}
else
{
<ul>
#foreach (YourObjects myobject in Model)
{
<li>#myObject.Name</li>
}
</ul>
}
You can do this by following these steps. In your controller, you return a partial view.
[HttpGet]
public virtual ActionResult LoadPartialViewDynamically()
{
var query = _repository.GetQuery();
return PartialView("_PartialViewName", query);
}
then in the view you have an empty div
<div id="partialgoeshere"></div>
and then load the partial view using jQuery:
function LoadPartialView() {
$.get("#Url.Action(MVC.ControllerName.LoadPartialViewDynamically())", { null }, function (data) {
$("#partialgoeshere").empty();
$("#partialgoeshere").html(data);
});
}
Hope this helps
I believe you can do something like this example, just using the change event on your dropdown instead. It's a simple jQuery call, you can find more on the jQuery website.
$("#dropdown").change(function() {
$("#destination").load("/Products/GetProduct", $(this).val(),
function(result) {
// do what you need to do
});
});
The first parameter is the view you need to call for the details.
The second parameter is the selected value.
The third parameter of the $.load function is the callback function, where you can parse the result and do what you need to do.
If you have a multiple select $(this).val() that will give you an array with the selected options.
If you want only return a Json object you may want to follow this example.
Use Ajax :)
http://api.jquery.com/jQuery.ajax/
Example:
$.post(window.gRootPath + "Customer/PartialView", { Question: questionId})
.done(function (data) {
$('#partialDiv').html(data.responceText);
});
You can use ajax to call action an then just insert html string using jQuery to the page where you want it to appear:
Server-side:
Render partial view to string
Renders partial view on server to html string, useful when you need to add partial view to ASP.NET MVC page via AJAX.
Client-side:
$('#yourDdl').change(function()
{
$.get('/InsertPartialViewUsingAjax', function (data)
{
$('#container').html(data);
});
});
The following article tells you how to do it with minimum javascript. Basically you return html instead of JSON to your response object.
https://www.simple-talk.com/content/article.aspx?article=2118

Resources