Asp.net MVC populate a list box with JQuery? - c#

I have a list of Payees in a drop down box on my form. I would like to populate a different drop down, based on the selected item of the Payee drop down, without post backs and all that.
So, I created a method in my controller that does the work:
private JsonResult GetCategories(int payeeId)
{
List<CategoryDto> cats = Services.CategoryServices.GetCategoriesByPayeeId(payeeId);
List<SelectListItem> items = new List<SelectListItem>();
foreach(var cat in cats)
{
items.Add(new SelectListItem {Text = cat.Description, Value = cat.CategoryId.ToString()});
}
return Json(items);
}
Now, I am unsure what to add to my view to get this to work.
At the moment, all I have is this:
<% using (Html.BeginForm())
{%>
<p>
<%=Html.DropDownList("SelectedAccountId", Model.Accounts, "Select One..", null) %>
</p>
<p>
<%=Html.DropDownList("SelectedPayeeId", Model.Payees, "Select One...", null) %>
</p>
<input type="submit" value="Save" />
<%
}%>
they populate fine... so when the user selects the SelectedPayeeId drop down, it should then populate a new (Yet to be created?) drop down which holds categories, based on the SelectedPayeeId.
So, I think I need to create a JQuery function (Never done JQuery.. so not even sure where it goes) which monitors the Payee drop down for an onChange event? And then call the method I created above. Does this sound right, and if so, can you guide me in how to achieve this?

Your reasoning so far is totally sound. First you are going to want to include the jquery library in your View / Master. You can download a copy of jquery from http://jquery.com/. Add the file to you project and include a <script src="/path/to/jquery.js"> to the <head> of your document. You are going to want to add another dropdown to your View (and probably another property to your model). We'll call this 'SelectedCategoryId:'
<%=Html.DropDownList("SelectedCategoryId", null, "Select One...", new { style = "display:none;"}) %>
We've set the style of this Drop Down to not be visible initially because there is nothing to select inside of it. We'll show it later after we generate some content for it. Now, somewhere on your page you will want to include a <script> block that will look something like this:
$(document).ready(function() { $('#SelectedPayeeId').change(function() {
$.ajax({
type: 'POST',
url: urlToYourControllerAction,
data: { payeeId: $(this).val() },
success: function(data) {
var markup = '';
for (var x = 0; x < data.length; x++ ) {
markup += '<option value="' + data[x].Value + '">'+data[x].Text+'</option>';
}
$('#SelectedCategoryId').html(markup).show();
}
}); }); });
This code binds the anonymous function written above to the DOM element with the ID of 'SelectedPayeeId' (in this case your dropdown). The function performs an AJAX call to the url of your method. When it receives the results of the request (your JSON you returned) we iterate over the array and build a string of the html we want to inject into our document. Finally we insert the html into the 'SelectedCategoryId' element, and change the style of the element so it is visible to the user.
Note that I haven't run this code, but it should be (almost) what you need. jQuery's documentation is available at http://docs.jquery.com/Main_Page and the functions I used above are referenced here:
.ready()
.change()
jQuery.ajax()
.html()
.show()

You'd need to make the GetCategories as a public method as it would correspond to an action handler in your controller.
Your jquery code can look like:
<script type="text/javascript">
$(function() {
$('#SelectedPayeeId').change(function() {
$.get('<%= Url.Action("GetCategories", "YourControllerName") %>',
{payeeId: $(this).val()},
function(data) {
populateSelectWith($("#Category"), data);
});
});
//Place populateSelectWith method here
});
</script>
The populateSelectWith can fill your dropdown with data like:
function populateSelectWith($select, data) {
$select.html('');
$select.append($('<option></option>').val('').html("MYDEFAULT VALUE"));
for (var index = 0; index < data.length; index++) {
var option = data[index];
$select.append($('<option></option>').html(option));
}
}
I have not tested this code, but I am hoping it runs okay.
You can find syntax for the jquery ajax get here
Since you are not posting any data to the server, you can might as well decorate your controller action with a [HttpGet] attribute

Related

Using #HTML.Action with Parameters to C# controller

In View, the user will check 1 or more names from what's displayed ...
<form name=chkAttend method=post onsubmit='return validate(this)'>
<div>
#if (Model.evModel.Participants != null)
{
foreach (var fi in Model.evModel.Participants)
{
<div>
#if (#fi.AttendedFlag != true)
{
<input type="checkbox" id="c_#fi.EnrollmentId" name="MyCheckboxes" value="#fi.EnrollmentId" />
<label for="c_#fi.EnrollmentId" aria-multiselectable="True"></label>
<span></span> #fi.EnrollmentId #fi.ParticipantName
}
</div>
}
}
<input type=submit value="Confirm Attendance">
</div>
</form>
After selecting names, call the function to identify which names checked. The checked names only need to be passed to the controller. The problem - I'm getting the error message: Error 49 The name 'id' does not exist in the current context
function validate(form) {
var id = ""
for (var i = 0; i < document.chkAttend.MyCheckboxes.length; i++)
{
if (document.chkAttend.MyCheckboxes[i].checked)
id += document.chkAttend.MyCheckboxes[i].value + ","
}
if (id == "")
{
alert("Place a check mark next to event's Participant")
}
else
{
#Html.Action("ConfirmAttendance", "Admin", new { eventid = #Model.evModel.Id, enrollid =id })
}
return false;
}
How do I pass ONLY the checked items as parameter for the function in my controller?
You cannot inject a server-side partial view into your code like that. As it stands (if you got around the id variable reference problem) you would literally inject a partial view inline into your Javascript which will create invalid Javascript!
Instead treat the JS as client-side only and feed information into the page that the Javascript will need in a way that is easy to access. You can inject global variables via injected JS code, but I strongly advise against that practice.
Instead your MVC page could inject the controller action URL and the event id as data- attributes like this:
<form name="chkAttend" method="post"
data-action="#Url.Content("~/Admin/ConfirmAttendance")"
data-eventid="#Model.evModel.Id">
Using Url.Content will ensure the URL is always site relative, even when hosted as a virtual application.
Your client-side code can then pick up the values from the form, add the selected id and call the server action using Ajax:
e.g.
function validate(form) {
var action = $(form).data('action');
var eventId = $(form).data('eventid');
The fun begins now because you need to call the server from the client-side, e.g. via Ajax, with your selected option and do something with the result to change the display.
$.ajax({
// Use constructed URL (action + event id + id)
url: action + "?eventid=" + eventId + "&enrollid=" + id,
type: "PUT"
success: function (data){
// Do something with the server result
}
});
You do not show your controller's ConfirmAttendance action so I cannot even guess what you are returning. Make sure it is suitable (could be as simple as a Boolean result or as complex as a partial view to insert into the page).

access/iterate over a C# list in jQuery

i am trying to make an image gallery with pictures fading in and out. I already have that part covered, but so far im hard coding the image url's in my .aspx page. I don't want this, i need it to be dynamic.
<script type="text/javascript">
$(function()
{ var img = $("img.x");
$(img).hide().eq(0).show();
var cnt = img.length
setInterval(imgRotate, 5000);
function imgRotate() {
$(img).eq((img.length++) % cnt).fadeOut("slow",
function() {
$(img).eq((img.length) % cnt).fadeIn("slow");
});
}
});
</script>
<body>
<form id="form1" runat="server">
<div>
<img class="x" alt="Image1" src="Desert.jpg"/>
<img class="x" alt="Image1" src="Lighthouse.jpg"/>
</div>
</form>
this makes the images fade in and out, which is good, but as you can see, i've hardcoded the images in this example. I can't use this for my application.
What i want to do is the following:
i want to pass a List<string> (codebehind) to the jQuery script that will just iterate over the list and replace the source url of the image.
i just want to do something like this in the jQuery script (pseudo-code):
int counter = 0;
var img = ListFromCodeBehind[counter];
//do some fading stuff
count++;
i've tried using <%=%> server tags, and so forth but to no avail. I've read lots of things but they all seem overly complicated for what i'm trying to achieve..
Why is everybody forcing you to use AJAX? There is no need to load image list in separate HTTP request. I assume your code comes from some aspx page. Therefore you can provide a public method in this Pages's class (lets call it GetImages()) that returns a string that looks like JavaScript array. I.e.
public string GetImages()
{
return "['Desert.jpg', 'Lighthouse.jpg']";
}
Then in you JavaScript code (that is placed in this Page's aspx file as well) you can call public method of Page's class with classic ASP syntax:
int counter = 0;
var ListFromCodeBehind = <%= this.GetImages() %>;
var img = ListFromCodeBehind[counter];
//do some fading stuff
count++;
which will finally print:
var ListFromCodeBehind = ['Desert.jpg', 'Lighthouse.jpg'];
and this is the result I believe you expect.
You can add a Web Method into your aspx page (code behind) that can be called by AJAX.
Your code behind method will return a string that contains the URL to the images, in a JSON format (so that JQuery knows how to iterate though it out of the box).
Have a look at this thread to have an idea of how to create a web method in an aspx code behind file. I'd do it via asp.net MVC though...much more straightforward
Calling an ASP.NET server side method via jQuery
//Controller
[HttpGet]
public JsonResult GetImageURLS()
{
var urls = GetUrls();
return Json(new { urls = urls }, JsonRequest.AllowGet);
}
//js file
$.ajax({ url : '/GetImageURLS/', success : function(e) { if (e && e.urls) {
var $images = $(".images");
for (var i in e.urls) {
$images.append('<img src="' + i.url + '" class="x" ' + ' alt="' + i.alt + '" /> ';
}
});
//html
<div class="images">
</div>
Try this for initial load of the images. Then call your function on them after the images are populated.
You can use AJAX and call a webservice in your Javascript to return your image list as follows:
function LoadImages() {
var url;
url = "WebServices/wsImages.asmx/GetImageList"
$.ajax({
type: "POST",
url: url,
contentType: "application/json; charset=utf-8",
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus);
},
success: function (response) {
var imgList = response.d;
//Loop through image list etc.
}
});
}

How can I make a continually updating query in MVC 3?

I am looking for a simple way to make a piece of text, which happens to be a number, on my view update in near-real-time.
I have a piece of text in my view that looks like this:
<% if (ViewData["TotalRecords"] != null)
{ %>
<%= ViewData["TotalRecords"].ToString() +
" records available to search."%>
<% } %><br />
I want ViewData["TotalRecords"] to be a constantly updating value, every 60 seconds or so.
The query underneath is:
public static string GetTotalRecords()
{
DataContext dc = new DataContext();
return dc.Records.Count().ToString("#,##0");
}
How can I make this into some kind of Ajax-enabled dynamic piece of text?
Move that part to separate action
public ActionResult TotalRecords()
{
var totalRecords = GetTotalRecords();
return PartialView(totalRecords);
}
In parent view, initially render that action with
<div id="totalRecords">
#Html.RenderAction("TotalRecords")`
</div>
And script with setInterval to reload TotalRecords action every 60 seconds
<script>
$(function(){
setInterval("reloadTotalRecords", 60 * 1000);
});
function reloadTotalRecords()
{
$('#totalRecords').load('#Url.Action("TotalRecords")');
}
</script>
There's going to have to be some JavaScript in there somewhere. A setTimeout could be used to call an ajax method that returns the number, which then is used to update the content in the browser.
You could use jQuery to target the specific element. There are some examples on this question.
I believe this should solve your question:
jQuery Ajax setTimeout JSON
Use the JavaScript setTimeout function to call an Ajax function every 60 seconds.
Something like:
function updateContent() {
$.ajax({
url: 'url',
cache:false,
success: function(data) {
$('#item-id').html(data.NewValue);
},
dataType: 'json'
});
}
$(function () {
setTimeout(updateContent, 60000);
}
I would jump into SignalR. Sounds interesting.

The best approach to send data to a Partial View Model and .html() being slow

Imagine I have a Partial View with a list of users ( loop ) where each user is another partial view with details about one.
foreach (var user in Model.Users)
{
<a href="#" onclick="JavascriptFunction(user.Id);">Details<a>
}
When I click the above Details link for one of the list items a popup (JQuery modal dialog() ) pops up with details about that selected user. Or at least that's the goal. I need to get the selected user details to a new popup that opened.
So now I need to populate the model behind the partial view that the popup will contain with user details before .dialog('Open') triggers.
Question: What's the best way, from within a Javascript function ( onclick JavascriptFunction function in the example above) to call an ActionMethod and populate the Partial View model before the dialog is displayed ?
Right now I'm doing it the following way but for whatever reason I'm getting major delays in data being rendered on the page. I see blank div for good 5-10 seconds before .html() finally displays data:
On the main list page:
<div id="userPopup"></div>
Javascript that suppose to load Partial view with User details from an ActionMethod:
$.post('#Url.Action("Details","User")', { id: userId},
function (data) {
$("#userPopup").html(data);
});
Possibly there is a way to pre-load a partial view on the page and then just load my data into its Model without re-writing the entire PartialView ?
That would be the ideal scenario but I don't think there is a way to do it, is there ?
Thank you in advance ! Don't hesitate to ask questions if anything sounds confusing.
I dont think you should preload all the user details on the main page, what if you have 1000+ users and the visitor is not clikcking the details link ! I would do it in this way. Whenever user clicks on the link, make a call to an action method which returns the data.
So in your main view,
#foreach(var user in Model.Users)
{
#Html.ActionLink(user.Name, "Details", "User",
new { Id = user.ID, }, new { #class ="popupLink" })
}
<script type="text/javascript">
$(function(){
$(".popupLink").click(function (e) {
e.preventDefault();
var url = this.href;
var dialog = $("#dialog");
if ($("#dialog").length == 0) {
dialog = $('<div id="dialog" style="display:hidden"></div>').appendTo('body');
}
dialog.load(
url,
{}, // omit this param object to issue a GET request instead a POST request, otherwise you may provide post parameters within the object
function (responseText, textStatus, XMLHttpRequest) {
dialog.dialog({
close: function (event, ui) {
dialog.remove();
},
modal: true,
width: 460
});
}
);
});
});
</script>
In User controller, have an action method called "Details which accepts the Id as parameter and return the View of User details
public ActionResult Details(int id)
{
var usre=repositary.GetUser(id);
return View(user);
}
Have your HTML markup for details in the DetailsView.
This code use jQuery UI model dialog. So you need to include that.

ASP.NET MVC & JQuery Dynamic Form Content

I would like to dynamically add fields to an ASP.NET MVC form with JQuery.
Example:
<script language="javascript" type="text/javascript">
var widgets;
$(document).ready(function() {
widgets = 0;
AddWidget();
});
function AddWidget() {
$('#widgets').append("<li><input type='text' name='widget" + widgets + "'/></li>");
widgets++;
}
</script>
<ul id="widgets">
</ul>
This works, but I was going to manually iterate the form values in the controller:
[AcceptVerbs("Post")]
public ActionResult AddWidget(FormCollection form)
{
foreach (string s in form)
{
string t = form[s];
}
return RedirectToAction("ActionName");
}
But it occurred to me when I send the user back to the Get Action in the Controller I will have to set the FormData with the values entered and then iteratively add the widgets with <% scripting.
What is the est way to do this in the current release (5 I believe)?
My solution could be something like this (pseudo-code):
<script language="javascript" type="text/javascript">
var widgets;
$(document).ready(function() {
widgets = 0;
<% for each value in ViewData("WidgetValues") %>
AddWidget(<%= value %>);
<% next %>
});
function AddWidget( value ) {
$('#widgets').append("<li><input type='text' name='widget" + widgets +
"'>" + value + "</input></li>");
widgets++;
}
</script>
<ul id="widgets">
</ul>
And in the controller:
[AcceptVerbs("Post")]
public ActionResult AddWidget(FormCollection form)
{
dim collValues as new Collection;
foreach (string s in form)
{
string t = form[s];
collValues.add( t )
}
ViewData("WidgetValues") = collValues;
return RedirectToAction("ActionName");
}
You can work out the details later
(sorry for mixing VB with C#, I'm a VB guy)
i might be missing the point here, but, do you need to actually post the data back to the controller via a form action? why not make an ajax call using jquery to post the data to the controller...or better yet a web service? send the data async and no need to rebuild the view with the data values sent in.
This works fine if the values are being consumed and never used again, however, if you plan on persisting the data and surfacing it through a the view, your model should really support the data structure. maybe a Dictionary<string, string> on the model.
I'm not a ASP.net developer but I know from PHP that you can use arrays as names for input fields
Ex:
<input type="text" name="widgets[]" />
<input type="text" name="widgets[]" />
You can then iterate through the post variable widgets as if it was an array of values.
No messing around with dynamicaly named variables etc.
As far as I understand the problem is to preserve the posted values in widgets.
I thik you can just render those widgest you wont to populate on the server during the View rendering.

Categories