I'm trying to figure out the best way (minimal effort) to apply filtering to a webgrid that I have displayed in my Main/Index view (MVC3).
I added a multiselet that would allow filtering by a certain column and I would like to catch the click event (which I already have implemented and working) per select item and then somehow re-invoke my Index() method that contains all the code to rebuild the view based on if it was invoked from a filter (multiselect).
What is the best way to go about this? I know that this is a broad ask but any information would be greatly appreciated.
Thanks!
You could place the multiselect inside a form. Then you have 2 possibilities to submit this form:
Using a submit button
Using the onchange event of the multiselect (in this case you will have to use javascript)
The first point is straightforward:
#using (Html.BeginForm())
{
#Html.ListBoxFor(x => x.SelectedItems, Model.Items)
<button type="submit">Filter</button>
}
To implement the second you could use jQuery and subscribe to the change event of the multiselect. First, let's give this multiselect an id so that we can more easily select it:
#using (Html.BeginForm())
{
#Html.ListBoxFor(x => x.SelectedItems, Model.Items, new { id = "filter" })
}
and then in a separate javascript file:
$(function() {
$('#filter').change(function() {
// when the selection changes we manually trigger the submission
// of the containing form
$(this).closest('form').submit();
});
});
In both cases the controller action that we are submitting to will take an array of strings as argument which will represent the selected values in the multiselect which will be used to filter the resultset.
Related
This is a slightly tricky question to put into words. Basically I've been trying to build a shopping cart page in KnockoutJS based on one of the examples in the the KnockoutJS website (http://knockoutjs.com/examples/cartEditor.html). However I wanted to make use of jQueryUI sliders so that I could adjust the values of each product in my cart.
This I've managed to get working OK and I can add a product (in this case Motorcars) to my basket and adjust the value and also increase/decrease the value depending on whether the car has a sports kit or is a convertible.
http://jsfiddle.net/FloatLeft/UjRrJ/
However, instead of adding a product (the "Add Car" button) and then choosing the car type, I want to be able to add a specific type (eg BMW, Ford) to the cart at the click of the button (eg clicking on the "Add BMW" button - this does nothing at the moment).
However my simple brain cant work out how to bind the button to a specific car in the collection. I think I can retrieve the car by creating a function that iterates over the collection and finds the car that has the type that matches a string, e.g.
function GetCar(carType) {
for (var i = 0; i < sampleCars.length; i++) {
if (sampleCars[i].Type == carType) {
return sampleCars[i];
}
}
}
So basically I want to know how I can bind the click event of "Add BMW" button to a particular car in the collection and have that added to my cart.
If you plan on making multiple buttons, you can create a function which can create your event handlers which can take in a car type.
self.addSpecificCarLine = function (carType) {
return function () {
var car = ko.utils.arrayFirst(sampleCars, function (car) {
return car.Type === carType;
});
var cartLine = new CartLine();
cartLine.car(car);
self.lines.push(cartLine);
};
};
Then you can bind to the handlers like so:
<button data-bind='click: addSpecificCarLine("BMW")'>Add BMW</button>
Updated fiddle
I'm building a calendar-based web app with fullcalendar, which is for college students to use. There are some categories I've defined. e.g, sport, art, mind, etc... every event in the fullcalendar would be assigned to a category.
What i want to do is: there're some checkboxes corresponding categories on the top of the calendar, and the user can check or uncheck some checkboxed to hide/show the related events
how would I achieve this?
One way is to put appropriate classes on each event by setting the 'className' property on the event objects you're sending to the calendar and use jquery to hide those events (e.g. $(.myClassName).hide()) when they check the checkboxes. The trouble is the events would vanish leaving a gap where they were which might not be what you want.
A better way would be to add a filter function to the events option when you first call fullCalendar like this:
fullCalendar({
...
events: {
url: ....,
success: function(events) {
$.map(events, function (e) {
if (userHasFilteredOut(e))
return null;
else
return e;
});
},
...
});
This will filter out the events before they are displayed. The function userHasFilteredOut returns true if the event object passed in is of a class the user's checkbox values indicate is filtered out. When the user checks or unchecks a checkbox, you will need to refetch all the events from the server. You need to do this:
$('#mycal').fullCalendar('refetchEvents');
I'm trying to create a single page form to create a 'work item'. One of the properties is a drop down for 'work item type'.
Depending on the work item type, the user may need to provide additional information in a name-value-pair style attributes grid (property sheet).
I would like to dynamically render the property sheet as soon as a work item type is selected or changed. Once the user provides all information, he would click submit to create the 'work item'.
This is what I have so far:
#using (Ajax.BeginForm("AttributeData", new AjaxOptions() { UpdateTargetId="AttributeDataCell" }))
{
<div style="float:left">
#{
Html.RenderPartial("CreateWorkItemPartialView");
}
</div>
<div id="AttributeDataCell" style="float:right">
#Html.Action("AttributeData", new {id = 1})
</div>
}
The AttributeData action in the controller simply renders the partial view:
public ActionResult AttributeData(int id = 0)
{
var attributes = _workItemDataService.ListWorkItemTypeAttributes(id);
return PartialView("EditWorkItemAttributesPartialView", attributes);
}
Now I would like to hook this up to the drop-down-list's selection event so that the partial view re-renders in the above table cell at every selection change. I would like to pass in the selected value as id.
One way is to force the form to submit itself (and thus re-render).
If that is the right approach, how do we go about it? Esp., how do we make only the property sheet to re-render?
If there is a better way to achieve the above, please indicate.
Thanks
You could subscribe to the .change() event of the dropdown and trigger an AJAX request:
$(function() {
$('#Id_Of_Your_Drop_Down').change(function() {
// This event will be triggered when the dropdown list selection changes
// We start by fetching the form element. Note that if you have
// multiple forms on the page it would be better to provide it
// an unique id in the Ajax.BeginForm helper and then use id selector:
var form = $('form');
// finally we send the AJAX request:
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: form.serialize(),
success: function(result) {
// The AJAX request succeeded and the result variable
// will contain the partial HTML returned by the action
// we inject it into the div:
$('#AttributeDataCell').html(result);
}
});
});
});
<script type="text/javascript">
$('#TextEdit').click(function () {
$('#ObnAdd').val('Save');
});
</script>
<% using (Html.BeginForm("Create", "ObnTextComponents",FormMethod.Post,new {#id = "TheForm"}))
{%>
I need to check the condition if my ObnAdd Button text is Add need to go Create ActionResult
if Button text is Save I need to go Save ActionResult..
how to check this Condition in BeginForm?
thanks
From your comments it seems that it's better to check for the value of the button on the Controller side. Because you can't change your aspx code after the page loads.
So, in your controller you should have something like this (make sure your ObnAdd has name=ObnAdd):
public ActionResult SaveCreate(FormCollection form, string ObnAdd)
{
if (ObnAdd == "Save")
{
//Do save
}
else if (ObnAdd == "Create")
{
//Do create
}
//here return RedirectToAction or whatever
return RedirectToAction("Index");
}
And your HTML:
<% using (Html.BeginForm("SaveCreate", "ObnTextComponents",FormMethod.Post,new {#id = "TheForm"}))
{%>
The ASP executes server-side before pageload and has no access to the dom. Whereas the javascript executes client-side during and after pageload.
Since changing the button text is done in javascript (after all the asp runs), the button will always have the same value during pageload, so the branch is unnecessary. Also note that the asp can't access the dom of the page it's creating to test for such things. You would need to either include a library that forms the dom tree for you or use standard text operators to check the value you're looking for (like a regex).
A simple solution to what I think you're doing here would be to maintain a hidden input on the form that is also updated when you update the button. Then you can have the button submit and the page handling the form can make the necessary decisions with all information available.
I have a partial view that is rendered within a main view. The partial view takes advantage of System.ComponentModel.DataAnnotations and Html.EnableClientValidation().
A link is clicked, and div containing the partial view is displayed within a JQuery.Dialog().
I then click the save button without entering any text in my validated input field. This causes the client side validation to fire as expected, and display the '*required' message beside the invalid field.
When the cancel button is clicked, I want to reset the client side MVC validation back to it's default state and remove any messages, ready for when the user opens the dialog again. Is there a recommended way of doing this?
This answer is for MVC3. See comments below for help updating it to MVC 4 and 5
If you just want to clear the validation-messages so that they are not shown to the user you can do it with javascript like so:
function resetValidation() {
//Removes validation from input-fields
$('.input-validation-error').addClass('input-validation-valid');
$('.input-validation-error').removeClass('input-validation-error');
//Removes validation message after input-fields
$('.field-validation-error').addClass('field-validation-valid');
$('.field-validation-error').removeClass('field-validation-error');
//Removes validation summary
$('.validation-summary-errors').addClass('validation-summary-valid');
$('.validation-summary-errors').removeClass('validation-summary-errors');
}
If you need the reset to only work in your popup you can do it like this:
function resetValidation() {
//Removes validation from input-fields
$('#POPUPID .input-validation-error').addClass('input-validation-valid');
$('#POPUPID .input-validation-error').removeClass('input-validation-error');
//Removes validation message after input-fields
$('#POPUPID .field-validation-error').addClass('field-validation-valid');
$('#POPUPID .field-validation-error').removeClass('field-validation-error');
//Removes validation summary
$('#POPUPID .validation-summary-errors').addClass('validation-summary-valid');
$('#POPUPID .validation-summary-errors').removeClass('validation-summary-errors');
}
I hope this is the effect you seek.
If you are using unobtrusive validation that comes with MVC you can simply do:
$.fn.clearErrors = function () {
$(this).each(function() {
$(this).find(".field-validation-error").empty();
$(this).trigger('reset.unobtrusiveValidation');
});
};
------------------------------------------------------------------------
Third Party Edit:
This mostly worked in my case, but I had to remove the $(this).find(".field-validation-error").empty(); line. This appeared to affect the re-showing of the validation messages when resubmitting.
I used the following:
$.fn.clearErrors = function () {
$(this).each(function() {
$(this).trigger('reset.unobtrusiveValidation');
});
};
and then called it like this:
$('#MyFormId input').clearErrors();
function resetValidation() {
$('.field-validation-error').html("");
}
You can simply define a new function in jQuery:
$.fn.resetValidation = function () {
$(this).each(function (i, e) {
$(e).trigger('reset.unobtrusiveValidation');
if ($(e).next().is('span')) {
$(e).next().empty();
}
});
};
and then use it for your input fields:
$('#formId input').resetValidation();
Thank you. I had a similar question for a slightly different scenario. I have a screen where when you click one of the submit buttons it downloads a file. In MVC when you return a file for download, it doesn't switch screens, so any error messages which were already there in the validation summary remain there forever. I certainly don't want the error messages to stay there after the form has been submitted again. But I also don't want to clear the field-level validations which are caught on the client-side when the submit button is clicked. Also, some of my views have more than one form on them.
I added the following code (thanks to you) at the bottom of the Site.Master page so it applies to all of my views.
<!-- This script removes just the summary errors when a submit button is pressed
for any form whose id begins with 'form' -->
<script type="text/javascript">
$('[id^=form]').submit(function resetValidation() {
//Removes validation summary
$('.validation-summary-errors').addClass('validation-summary-valid');
$('.validation-summary-errors').removeClass('validation-summary-errors');
});
</script>
Thanks again.
You can tap into the validation library methods to do this.
There are two objects of interest: FormContext and FieldContext. You can access the FormContext via the form's __MVC_FormValidation property, and one FieldContext per validated property via the FormContext's fields property.
So, to clear the validation errors, you can do something like this to a form:
var fieldContexts = form.__MVC_FormValidation.fields;
for(i = 0; i < fieldContexts.length; i++) {
var fieldContext = fieldContexts[i];
// Clears validation message
fieldContext.clearErrors();
}
// Clears validation summary
form.__MVC_FormValidation.clearErrors();
Then, you can hook that piece of code to whichever event you need.
Sources for this (quite undocumented) insight:
http://bradwilson.typepad.com/presentations/advanced-asp-net-mvc-2.pdf (Mentions FieldContext)
https://stackoverflow.com/a/3868490/525499 (For pointing out this link, which metions how to trigger client-side validation via javascript)
In order to complete clear the validation artifacts including the message, the coloured background of the input field, and the coloured outline around the input field, I needed to use the following code, where this was (in my case) a Bootstrap modal dialog containing an imbedded form.
$(this).each(function () {
$(this).find(".field-validation-error").empty();
$(this).find(".input-validation-error").removeClass("input-validation-error");
$(this).find(".state-error").removeClass("state-error");
$(this).find(".state-success").removeClass("state-success");
$(this).trigger('reset.unobtrusiveValidation');
});
Here you can use simply remove error message
$('.field-validation-valid span').html('')
OR
$('.field-validation-valid span').text('')
I've this issue for "Validation summery" after form ajax submit and done it like this:
$form.find('.validation-summary-errors ul').html('');
and complete code is:
$("#SubmitAjax").on('click', function (evt) {
evt.preventDefault();
var $form = $(this).closest('form');
if ($form.valid()) {
//Do ajax call . . .
//Clear validation summery
$form.find('.validation-summary-errors ul').html('');
}
});