popup a dialog and submit partial view in asp.net mvc - ajax

So what I am trying to do here is that in the View,
when I click on the button, I want to pass some values generated from the foreach loop (in my case Country and City) to the javascript function.
Inside that javascript function, I want to open up a dialog(partial view) by passing those values (countryName, cityName) to the controller.
Hence in my controller, it will pass those values to the partial view which will be appeared as a dialog and can submit the form.
I've tried with the version without the pop-up dialog (it worked), but having a hard time doing it with a dialog. #3 works btw, but I think I am having a trouble with #1 and #2. Any help would be appreciated. Thanks.
View:
#model IEnumerable<test.Models.Employee>
<table class="table">
<tr>
<th>Country</th>
<th>City</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Country)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
<button onclick="OpenDialog(item.Country, item.City)">
Open Dialog
</button>
</td>
</tr>
}
</table>
<div id="dialog"></div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/jquery-ui-1.12.0.js"></script>
<script>
function OpenDialog(countryName, cityName) {
$('#dialog').dialog({
autoOpen: true,
width: 400,
resizable: false,
title: 'My Table',
modal: true,
open: function(event, ui) {
$(this).load('#Url.Action("getEmployee", "Employee", new
{
country = countryName,
city = cityName
})');
},
buttons: {
"Close": function () {
$(this).dialog("close");
}
}
});
}
</script>
}
Controller:
public ActionResult getEmployee(string country, string city)
{
var viewModel = new EmployeeViewModel()
{
Country = country,
City = city
};
return PartialView("EmployeeDialog", viewModel);
}
Partial View:
#model test.ViewModels.EmployeeViewModel
#using (Html.BeginForm("PostEmployee", "Employee", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.Country)
#Html.HiddenFor(model => model.City)
#Html.EditorFor(model => model.Comments)
<input type="submit" value="Submit"/>
}

#Url.Action() is razor code and is parsed in the server before its sent to the view. countryName and cityName are javascript variables and do not even exist at that point (they are not in scope). Change the code in the OpenDialog() function to
var url = '#Url.Action("getEmployee", "Employee")';
var data = { country: countryName, city: cityName };
$(this).load(url, data);
As a side note, there is really no need to be calling the server each time to return values that you already have in the view. You could just render the form in the dialog initially (for a default EmployeeViewModel and then in the OpenDialog just set the values of the inputs for properties Country and City, for example $('#Country').val(countryName);

Related

Populate Multi-select list from Ajax in Knockout

I have an editable table based off of the Knockoutjs example. I've been trying to populate a multi-select dropdown list from an AJAX call to ASP MVC controller. I've looked through this example, this one, and this one but am still having issues getting it to work.
Here's the html:
<tbody data-bind='foreach: users' class="table-striped">
<tr>
<td><input class='required number form-control' maxlength="9" stringlength="9" data-bind='value: id, uniqueName: true' /></td>
<td><input class='required form-control' data-bind='value: firstName' /></td>
<td><input class='required form-control' data-bind='value: lastName' /></td>
<td>
<select data-bind="options: MAMUserGroupsListOptions, selectedOptions: MAMSelectedGroup">
<!--dropdown list goes here-->
</select>
</td>
<td><a href='#' data-bind='click: $root.removeUser'>Delete</a></td>
</tr>
</tbody>
Here's the javascript for the knockout portion:
var UserModel = function (users) {
var self = this;
self.users = ko.observableArray(users);
//add user
self.addUser = function () {
self.users.push({
id: "",
firstName: "",
lastName: "",
MAMUserGroupsListOptions: "",
MAMUserGroups: ""
});
};
//remove user
self.removeUser = function (user) {
self.users.remove(user);
};
var viewModel = new UserModel([
{
id: ko.observable(""), firstName: ko.observable(""), lastName: ko.observable(""),
MAMUserGroupsListOptions: ko.observable(),//this is where I need to populate
MAMSelectedGroups: ko.observable(),//this is the result of the multiselect
}
]);
ko.applyBindings(viewModel);
Here's the controller:
[HttpGet]
public ActionResult MAMUserGroupsList()
{
var MAMUserGroupsListOptions = db.MAMUserGroupsListModels.Select(x => new {
MAMUserGroupName = x.MAMUserGroupName
}).ToList();
return Json(MAMUserGroupsListOptions, JsonRequestBehavior.AllowGet);
}
When the controller is called via AJAX, this is what returns:
{MAMUserGroupName: "MAMGroup1"}, {MAMUserGroupName: "MAMGroup2"}, etc...
I'm trying to get the multi-select dropdown to have "MAMGroup1", MAMGroup2, etc.
I've been banging my head against the wall on this- any help would be much appreciated.
Looks like you just want to map the array of objects to extract the one value of interest. If you start with your result in a variable named ajaxResult,
MAMUserGroupsListOptions(ajaxResult.map(obj => obj.MAMUserGroupName));
will assign the values to your observable array. Or if the value is available to you when you're creating your viewmodel,
MAMUserGroupsListOptions: ko.observable(ajaxResult.map(obj => obj.MAMUserGroupName))

How can I make a loop to repeat my method for each item?

there is my issue. In a controller, I have this method which export my view in a file when I click a button.
public ActionResult Export(string searchString, int searchOrder = 0)
{
var user = from m in db.Orders select m;
if (!String.IsNullOrEmpty(searchString))
{
user = user.Where(s => s.ClientID.Contains(searchString));
}
Response.AddHeader("Content-Type", "application/vnd.ms-excel");
return this.View(user);
}
My Index view :
#model IEnumerable<MyApp.Models.Order>
#{
ViewBag.Title = "Index";
}
<h2>Orders Historic</h2>
<div id="orderDiv">
#using (Html.BeginForm("Export", "Historic", FormMethod.Get))
{
<p>
Generate Order with ClientID :&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
#Html.TextBox("searchString")
<input type="submit" value="GENEREMOI" />
</p>
}
</div>
And my Export view :
#model IEnumerable<KrysGroup.Models.Order>
<table cellpadding="3" cellspacing="3">
<tr>
<td width="12%" align="center">
Client Name/ID
</td>
<td width="15%" align="center">
N° Order
</td>
OTHER TD....
</tr>
#foreach (var item in Model)
{
TimeSpan result = DateTime.Now - item.OrderDate;
if (result.Days < 31)
{
<tr border="1" bgcolor="#Odd">
<td> #Html.DisplayFor(modelItem => item.Username) </td>
<td> #Html.DisplayFor(modelItem => item.OrderId) </td>
<td>
<ul style="list-style-type:none; padding:0; margin:0">
#if (item.OrderDetails != null)
{
foreach (var o in item.OrderDetails)
{
if (o.Pack == null)
{
<li> #Html.DisplayFor(modelItem => o.Product.Name) </li>
}
else
{
<li> <text>Pack</text> #Html.DisplayFor(modelItem => o.Pack.Name) </li>
}
}
}
</ul>
</td>
OTHER TD...
</table>
So, in my view, I inform in a textbox a ClientID and when I click the button, it export in a file all the fields in my table with this ClientID.
I would like to automate this action, that is to say I would like write a method or something for, when I click on the button, it executes this export() method for each clientId it meet in my table.
I hope I was clear enough, sorry for my english..
Thanks for your answers, links, tips whatever.
You can write a partial view typed to a list of Id's that loads when you click the button.
So in the controller you have a method converts what you want and returns a view that is typed to the conversion of your model.
In your main view you have a div that will be populated with a partial view after the click-event of the original button.
#Ajax.ActionLink("Name", "NameOfTheAction", "NameOfTheController",
new { id = itemId },
new AjaxOptions { HttpMethod = "Get", UpdateTargetId = "divInMainView", OnSuccess = "Do Something (js)" },
new { html-props })
How to populate is up to you, in your view

MVC3 unobtrusive validators not being written into partial page

When the following code is retrieved via an ajax call no validators are written into the view. Any number of these partial views might be added to the page and the textbox gets a datepicker, so that's why the unique id is generated. I certainly appreciate any help.vie
#using Nautilus.Core.Model.Enumeration
#using Nautilus.Web.Models
#using Nautilus.Web.Views.Tools
#model IntensityHistoryModel
<tr>
<td class='removeIntensityScore' title='Click to remove this item.'></td>
<td>
<span></span>
</td>
<td>
#Html.ValidationMessageFor(m => m.IntensityDateGUID)
#Html.TextBoxFor(m => m.IntensityDate, new { id = Model.IntensityDateGUID, #class = "intensityScoreDate", style = "width:120px" })
</td>
<td>
#Html.DropDownList("IntensityScore", ViewHelper.GetSelectListWithDescriptionFromEnum<IntensityScore.Values>("", new[] { "0" }), " -- Select -- ", new { style = "width:150px;margin:0" })
</td>
</tr>
When you do the ajax call, in the callback function you have to call again the validation.
Something like that
$("#myDiv").load($("#myA").attr("href"), function () {
$.validator.unobtrusive.parse("#myFormPartial");
});
It's not including the validation data attributes because the elements are not in a form. The workaround is to initialize a FormContext for your partial view:
#{
ViewContext.FormContext = new FormContext();
}
<tr><!-- your partial content --></tr>

MVC 3 Razor - Form not posting back to controller

I am using MVC 3 and Razor, attempting to post a form back to a controller from a telerik window (telerik.window.create) that loads a partial view. Im not sure how to post this so ill just post the code in order of execution and explain it as I go.
First an anchor is clicked, and onClick calls:
function showScheduleWindow(action, configId) {
var onCloseAjaxWindow = function () { var grid = $("#SubscriptionGrid").data("tGrid"); if (grid) { grid.rebind(); } };
CreateAjaxWindow("Create Schedule", true, false, 420, 305, "/FiscalSchedule/" + action + "/" + configId, onCloseAjaxWindow);
}
And the CrateAjaxWindow method:
function CreateAjaxWindow(title, modal, rezible, width, height, url, fOnClose) {
var lookupWindow = $.telerik.window.create({
title: title,
modal: modal,
rezible: rezible,
width: width,
height: height,
onClose: function (e) {
e.preventDefault();
lookupWindow.data('tWindow').destroy();
fOnClose();
}
});
lookupWindow.data('tWindow').ajaxRequest(url);
lookupWindow.data('tWindow').center().open();
}
Here is the partial view that is being loaded:
#model WTC.StatementAutomation.Web.Models.FiscalScheduleViewModel
#using WTC.StatementAutomation.Model
#using WTC.StatementAutomation.Web.Extensions
#using (Html.BeginForm("Create", "FiscalSchedule", FormMethod.Post, new { id = "FiscalScheduleConfigForm" }))
{
<div id="FiscalScheduleConfigForm" class="stylized">
<div class="top">
<div class="padding">
Using fiscal year end: #Model.FiscalYearEnd.ToString("MM/dd")
</div>
<div class="padding Period">
<table border="0">
<tr>
<th style="width: 120px;"></th>
<th>Effective Date</th>
<th>Next Run</th>
<th>Start From Previous</th>
</tr>
<tr>
<td>
#Html.CheckBoxFor(m => m.HasMonthly)
<label>Monthly</label>
</td>
<td>
#{ var month = Model.GetForFiscalPeriod(FiscalPeriodStatementSchedule.FiscalPeriod.Monthly);}
#month.BaseSchedule.StartDate.ToString("MM/01/yyyy")
</td>
<td>
#month.BaseSchedule.NextScheduleRun.ToString("MM/dd/yyyy")
</td>
<td class="previous">
#(month.HasRun ? Html.CheckBoxFor(m => month.BaseSchedule.StartFromPreviousCycle, new { #disabled = "disabled", #readonly = "readonly" }) : Html.CheckBoxFor(m => month.BaseSchedule.StartFromPreviousCycle))
</td>
</tr>
<tr>
<td>
#Html.CheckBoxFor(m => m.HasQuarterly) Quarterly
</td>
<td>
#{ var quarter = Model.GetForFiscalPeriod(FiscalPeriodStatementSchedule.FiscalPeriod.Quarterly);}
#quarter.BaseSchedule.StartDate.ToString("MM/01/yyyy")
</td>
<td>
#quarter.BaseSchedule.NextScheduleRun.ToString("MM/dd/yyyy")
</td>
<td class="previous">
#(quarter.HasRun ? Html.CheckBoxFor(m => quarter.BaseSchedule.StartFromPreviousCycle, new { #disabled = "disabled", #readonly = "readonly" }) : Html.CheckBoxFor(m => quarter.BaseSchedule.StartFromPreviousCycle))
</td >
</tr>
<tr>
<td>
#Html.CheckBoxFor(m => m.HasAnnual) Annual
</td>
<td>
#{ var annual = Model.GetForFiscalPeriod(FiscalPeriodStatementSchedule.FiscalPeriod.Annual);}
#annual.BaseSchedule.StartDate.ToString("MM/01/yyyy")
</td>
<td>
#annual.BaseSchedule.NextScheduleRun.ToString("MM/dd/yyyy")
</td>
<td class="previous">
#(annual.HasRun ? Html.CheckBoxFor(m => annual.BaseSchedule.StartFromPreviousCycle, new { #disabled = "disabled", #readonly = "readonly" }) : Html.CheckBoxFor(m => annual.BaseSchedule.StartFromPreviousCycle))
</td>
</tr>
<tr>
<td>
#Html.CheckBoxFor(m => m.HasSemiAnnual) Semi-annual
</td>
<td>
#{ var semi = Model.GetForFiscalPeriod(FiscalPeriodStatementSchedule.FiscalPeriod.SemiAnnual);}
#semi.BaseSchedule.StartDate.ToString("MM/01/yyyy")
</td>
<td>
#semi.BaseSchedule.NextScheduleRun.ToString("MM/dd/yyyy")
</td>
<td class="previous">
#(semi.HasRun ? Html.CheckBoxFor(m => semi.BaseSchedule.StartFromPreviousCycle, new { #disabled = "disabled", #readonly = "readonly" }) : Html.CheckBoxFor(m => semi.BaseSchedule.StartFromPreviousCycle))
</td>
</tr>
</table>
</div>
<div class="padding StartDay">
<span>Run on day:</span>
#Html.TextBoxFor(model => model.StartDay)
<span>of every period.</span>
</div>
</div>
<div class="bottom">
<div class="padding">
<div style="float: left;">
#if (Model.ShowSuccessSave)
{
<div id="successSave" class="label">Changes saved succesfully</div>
}
#Html.ValidationSummary(true)
#Html.HiddenFor(x => x.SubscriptionId)
#Html.HiddenFor(x => x.DeliveryConfigurationId)
#Html.HiddenFor(x => x.FiscalYearEnd)
</div>
<a id="saveSchedule" class="btn" href="">Save</a>
</div>
</div>
</div>
}
<script type="text/javascript">
$(function () {
$('a#saveSchedule').click(function () {
$(this).closest("form").submit();
return false;
});
});
</script>
And finally the controller method:
[HttpPost]
public ActionResult Create(FormCollection formValues, int subscriptionId, int deliveryConfigurationId, int startDay, DateTime fiscalYearEnd)
{
if (ModelState.IsValid)
{
var selectedSchedules = GetCheckedSchedulesFromForm(formValues);
var startFromPrevious = GetFromPreviouSelections(formValues);
this.AddModelErrors(_fiscalScheduleService.AddUpdateSchedules(selectedSchedules, subscriptionId, deliveryConfigurationId, startDay, startFromPrevious));
}
return new RenderJsonResult { Result = new { success = true, action = ModelState.IsValid ? "success" : "showErrors",
message = this.RenderPartialViewToString("_FiscalScheduleConfigForm",
BuildResultViewModel(deliveryConfigurationId, subscriptionId, fiscalYearEnd, ModelState.IsValid)) } };
}
As you can see I am using jQuery to post back to the controller, which I have done on several occasions in the applicaiton, this seems to work fine normally. But with this form, for some reason it is not posting back or stepping into the Create method at all. I am speculating that it has something to do with the parameters on the controller method. But I am fairly new to MVC (coming from ASP.NET world) so Im not really sure what I am doing wrong here. Any help would be greately appreciated!
I was able to get it to post to the controller by modifying the textboxfor for the startDay:
Changed from:
#Html.TextBoxFor(model => model.StartDay)
To:
#Html.TextBoxFor(model => model.StartDay, new { id = "startDay" })
My guess is that you're running on a virtual directory in IIS? That url you're generating is likely the culprit.
Hit F12, check out the network tab (and enable tracing) and see what it's trying to request.
Instead of building the link through text, why not use #Url.Action()? You could store this in an attribute on the a tag (like in an attribute called data-url, for example) and then use that info to make your call. It's pretty easy to pull out the attribute with jQuery, something like this:
$('.your-link-class').click(function(){
var url = $(this).attr('data-url');
// proceed with awesomesauce
});
Would something like that work for you?
[shameless self plug] As far as the controller action signature goes, you might want to look into model binding if you can. One simple class and many of your headaches will go away. You can read more here, read the parts on model binding. There are downloadable samples for different approaches.
Cheers.

Partial postback of page with dropdownlist using AJAX on MVC3 page EF4

I have a dropdownlist which lists Country names
When user select any country from dropdown list.Based on the country selection, I need data(AgencyName, AgencyAddr,Pincode) to be loaded from database and fill the TextBoxs on the right side.The selected country in the dropdown should remain selected.
on selection change of dropdownlist ,I do not want the entire page to postback .Please help me
Here is my EF4 - ModelClasses
public class Country
{
public int CountryID { get; set; }
public string CountryName { get; set; }
}
public class AgencyInfo
{
public int CountryID { get; set; }
public string AgencyName { get; set; }
public string AgencyAddr { get; set; }
public int Pincode { get; set; }
}
Here is my MVC4 razor page Index.cshtml
#using (Ajax.BeginForm(
"Index",
"Home",
new AjaxOptions { UpdateTargetId = "result" }
))
{
#Html.DropDownList("SelectedCountryId", Model.CountryList, "(Select one event)")
}
<div id=’result’>
<fieldset>
<legend>Country Details: </legend>
<div>
<table>
<tr>
<td>
<span>Country Name </span>
<br />
#Html.EditorFor(model => model.Countries.Name)
#Html.ValidationMessageFor(model => model. Countries.Name)
</td>
<td>
<span>Agency Name </span>
<br />
#Html.EditorFor(model => model.AgencyInfo.AgencyName)
#Html.ValidationMessageFor(model => model.AgencyInfo.AgencyName)
</td>
</tr>
<tr>
<td>
<span>Address Info </span>
<br />
#Html.EditorFor(model => model. AgencyInfo.Address)
#Html.ValidationMessageFor(model => model. AgencyInfo.Address)
</td>
<td>
<span>Pin Code </span>
<br />
#Html.EditorFor(model => model. AgencyInfo.PinCode)
#Html.ValidationMessageFor(model => model. AgencyInfo.PinCode)
</td>
</tr>
<tr>
<td>
<input type="submit" value="Modify" /><input type="submit" value="Delete" />
</td>
<td>
<input type="submit" value="Save" /><input type="submit" value="View Resources" />
</td>
</tr>
</table>
</div>
</fieldset>
</div > #end of result div#
Any suggestions ? Thank you
You want to use ajax.
Add an event handler to monitor the selection change. When the drop down changes, get the current country and send the ajax request. When the ajax request returns update the DOM with jQuery.
Example view:
<p id="output"></p>
<select id="dropDown"><option>Option 1</option>
<option>Option 2</option></select>
<script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
<script>
$(document).ready(function () {
$("#dropDown").change(function () {
var selection = $("#dropDown").val();
var dataToSend = {
country: selection
};
$.ajax({
url: "home/getInfo",
data: dataToSend,
success: function (data) {
$("#output").text("server returned:" + data.agent);
}
});
});
});
</script>
Example controller method:
public class HomeController : Controller
{
[HttpGet]
public JsonResult GetInfo(string country)
{
return Json(new { agent = country, other = "Blech" }, JsonRequestBehavior.AllowGet);
}
}
Some other examples:
adding a controller method to handle ajax request:
http://www.cleancode.co.nz/blog/739/ajax-aspnet-mvc-3
calling ajax and updating DOM:
http://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_ajax2

Resources