on check box check send value to partial view and update it mvc 3 - ajax

i have two partial view one is having a 5 checkbox (for filtering) and another will display the filtered data.
<input type="checkbox" data-toggle="checkbox" id="2000-5000"/>Rs.2000-Rs.5000
<input type="checkbox" data-toggle="checkbox" id="2000-5000"/>Rs.2000-Rs.5000
and with help of jquery am sending the request to controller..
public PartialViewResult PhonesPartail(int? id,string where)
{
var list = paginateRsult(id, "", where).ToList();
ViewData["totalpages"] = totalPages;
return PartialView("_phonelist",list);
}
and the jquery
$(document).on("change", ".price-checkbox input[type=checkbox]", function () {
if ($(this).is(":checked")) {
var prange = $(this).attr("id");
var parray = prange.split('-');
var whereclause = "price>=" + parray[0] + " and price <=" + parray[1];
$.ajax({
url: '../../Phones/PhonesPartail',
data: { where: whereclause },
type: 'POST',
success: function (data) {
$("#phone-list").append(data);
}
});
}
});
now the list which is returned , is getting added to the div with entire html page.. means again the html page is getting added in the div..
any solution..
Thanks in advance...

use html() function of jquery
It will paste data returned by partial view in to a div rather then appending it to div
$("#phone-list").html(data);

Related

How can I implement a dynamic form in TYPO3?

I have created a extension to manage some courses and now I want to add some dynamic to one of my forms. This form contains two select fields. The first select field specify a course category and the second one a course. Currently I get always all categories and all courses no matter which category is selected.
Now I would like that a user can only select a course which belongs to a selected category, but I don't know how I can implement this.
I have tried to use a typeNum and some ajax, but I don't know how I can change the form model with the ajax call and without a page reload.
My template for this form looks like the following:
<f:layout name="Default" />
<f:section name="main">
<div class="sidebar-view">
<a id="form"></a>
<f:form action="list" name="form" object="{form}" section="form">
<fieldset>
<f:render partial="FormErrors" arguments="{field: 'form.category'}" />
<f:form.select class="category" property="category" options="{categoryOptions}" optionValueField="key" optionLabelField="value" prependOptionLabel="{f:translate(key: 'LLL:EXT:courses/Resources/Private/Language/locallang_db.xlf:tx_courses_domain_model_form.category')}" />
<f:render partial="FormErrors" arguments="{field: 'form.course'}" />
<f:form.select property="course" options="{courseOptions}" optionValueField="key" optionLabelField="value" prependOptionLabel="{f:translate(key: 'LLL:EXT:courses/Resources/Private/Language/locallang_db.xlf:tx_courses_domain_model_form.course')}" />
<f:form.hidden class="id" property="pageId" />
<f:form.submit name="send" value="{f:translate(key: 'LLL:EXT:courses/Resources/Private/Language/locallang_db.xlf:tx_courses_domain_model_form.submit')}" />
</fieldset>
</f:form>
</div>
</f:section>
As you can see it is a simple form with two select fields, a submit button and a hidden field which stores the page id. I don't want to submit the form when the category is changed so I think there is no way to implement this dynamic without ajax.
For this reason I have implemented the following typenum:
obj.ajaxPrototype = PAGE
obj.ajaxPrototype {
typeNum = 0
config {
disableAllHeaderCode = 1
additionalHeaders = Content-type: text/plain
xhtml_cleaning = 0
debug = 0
no_cache = 1
admPanel = 0
}
}
ajaxCall < obj.ajaxPrototype
ajaxCall {
typeNum = 1001
10 < tt_content.list.20.courses_p1
}
After that I have added some javascript (jQuery) to execute a controller action via ajax when the select field is changed:
$(document).ready(function() {
$('.tx-courses select:first-of-type').on('change', function() {
$.ajax({
method: "POST",
url: "index.php?id=" + $('.id').val(),
data: "type=1001&tx_courses_p1[action]=check&tx_courses_p1[form][category]="+$('.category').val(),
success: function(msg) {
alert(msg);
}
});
});
});
Simple action:
/**
* check action
*
* #return void
*/
public function checkAction() {
return 'ajax call fired';
}
If I change the select field I get the message "ajax call fired". So my controller action will be executed and I might implement some "get courses by requested category id" logic and so on now, but how can I update the form from above which will be rendered by my sidebarAction with the ajax call and without a page reload?
Ok, I found a way to get it work.
At first I changed the ontent type of my typeNum from above to json, because I want to work with json.
additionalHeaders = Content-type: application/json
Then I changed my ajax call:
$(document).ready(function() {
var arr;
var ajaxCall = function() {
$.ajax({
method: "POST",
url: "index.php?id=" + $('.id').val(),
data: "type=1001&tx_courses_p1[action]=check&tx_courses_p1[form][category]="+$('.category').val(),
success: function(msg) {
$('.tx-courses .course option:not(:first-child)').remove();
arr = $.map(msg, function(el) { return el });
arr.sort();
$.each(arr, function(i, val) {
$('.tx-courses .course').append('<option value="'+val+'">'+val+'</option>');
});
}
});
};
// init (if someone submitted the form, but forgot to select a category)
ajaxCall();
// someone changed the category
$('.tx-courses .category').on('change', function() {
ajaxCall();
});
});
And my controller action for this ajax request looks as follows:
/**
* check action
*
* #return string
*/
public function checkAction() {
// get arguments
$args = $this->request->getArguments();
// create container for courses which are depended on selected category
$coursesBySelectedCategory = array();
// check if category was posted and category exists
if (isset($args['form']['category']) && $this->courseRepository->categoryExists($args['form']['category'])) {
// get all courses which belongs to this category
$courses = $this->courseRepository->findByCategoryId($args['form']['category']);
} else {
// get all courses
$courses = $this->courseRepository->findAllNotExpiredCourses();
}
// store course names
foreach($courses as $course) {
$coursesBySelectedCategory[] = $course->getName();
}
// remove double entries
$coursesBySelectedCategory = array_unique($coursesBySelectedCategory);
return json_encode($coursesBySelectedCategory);
}
Your feedback is welcome :).

MVC4 WebGrid loaded from Ajax form - multiple calls to Controller when sorting and paging

I have the following in my view
#using (Ajax.BeginForm("Search", "Home", null,
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "gridContent",
}, new { #class = "search" }))
{
<input type="submit" value="Search" />
}
<div id="gridContent">
</div>
This is what returns /Home/Search
#model List<TestTable.Models.People>
#{
Layout = null;
}
#{
var grid = new WebGrid(Model, canPage: true, canSort: true, rowsPerPage: 5, ajaxUpdateContainerId: "tableDiv"); grid.Pager(WebGridPagerModes.NextPrevious);
}
<div id="tableDiv">
#grid.GetHtml(
columns: grid.Columns(
grid.Column("Name", " Name")
))
</div>
This works good in MVC3, however MVC4 sends a script on every new search,
causing one new additional request for each submit button click for every paging and sorting query.
Here is how it looks:
"http://localhost:59753/Home/Search".
"http://localhost:59753/Home/Search?sort=Name&sortdir=ASC&__swhg=1394297281115"
"http://localhost:59753/Home/Search".
"http://localhost:59753/Home/Search?sort=Name&sortdir=ASC&__swhg=1394297284491"
"http://localhost:59753/Home/Search?sort=Name&sortdir=ASC&__swhg=1394297284490"
Any ideas how to fix that?
Thanks in advance!
The reason this is happening is because the WebGrid control injects the following script into your DOM every time you render it (in your case every time you submit the AJAX form because the WebGrid is situated in a partial that you are injecting in your DOM):
<script type="text/javascript">
(function($) {
$.fn.swhgLoad = function(url, containerId, callback) {
url = url + (url.indexOf('?') == -1 ? '?' : '&') + '__swhg=' + new Date().getTime();
$('<div/>').load(url + ' ' + containerId, function(data, status, xhr) {
$containerId).replaceWith($(this).html());
if (typeof(callback) === 'function') {
callback.apply(this, arguments);
}
});
return this;
}
$(function() {
$('table[data-swhgajax="true"],span[data-swhgajax="true"]').each(function() {
var self = $(this);
var containerId = '#' + self.data('swhgcontainer');
var callback = getFunction(self.data('swhgcallback'));
$(containerId).parent().delegate(containerId + ' a[data-swhglnk="true"]', 'click', function() {
$(containerId).swhgLoad($(this).attr('href'), containerId, callback);
return false;
});
})
});
function getFunction(code, argNames) {
argNames = argNames || [];
var fn = window, parts = (code || "").split(".");
while (fn && parts.length) {
fn = fn[parts.shift()];
}
if (typeof (fn) === "function") {
return fn;
}
argNames.push(code);
return Function.constructor.apply(null, argNames);
}
})(jQuery);
</script>
This script is baked into the WebGrid helper and there's not much you could do against it once you enable AJAX on your WebGrid. In this script you will undoubtedly notice how it subscribes to the click event of the pagination anchors in a lively manner:
$(containerId).parent().delegate(containerId + ' a[data-swhglnk="true"]', 'click', function() {
$(containerId).swhgLoad($(this).attr('href'), containerId, callback);
return false;
});
which is all sweet and dandy except that every time you click on the submit button you are injecting this script into your DOM (because your WebGrid is in the partial) and basically you are subscribing to the click event of the pagination anchors multiple times.
It would have been great if the authors of this WebGrid helper have left you the possibility to replace this delegate with a standard click handler registration which would have been ideal in this case as it wouldn't create multiple event registrations, but unfortunately the authors didn't left you with this possibility. They just assumed that the WebGrid would be part of the initial DOM and thus their script.
One way would be to subscribe to the OnBegin handler of the Ajax form submission and simply undelegate the existing event handlers because they will be overwritten once you refresh the DOM:
#using (Ajax.BeginForm("Search", "Home", null,
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
OnBegin = "callback",
HttpMethod = "POST",
UpdateTargetId = "gridContent",
}, new { #class = "search" }))
{
<input type="submit" value="Search" />
}
<div id="gridContent"></div>
<script type="text/javascript">
var callback = function (a) {
$('#tableDiv').parent().undelegate('#tableDiv a[data-swhglnk="true"]', 'click');
};
</script>
But to be honest, personally I just hate all this automatically generated scripts and simply never use any Ajax.* helpers stuff as well as activating AJAX on the WebGrid. I prefer to unobtrusively AJAXify the elements I want using jQuery which provides me with far greater control over what's happening. This way I would simply have externalized the bunch of automatically generated javascript by the WebGrid helper into a separate js file that I would have included in my View and there wouldn't be any needs of unregistering and cleaning the mess of the duplicate event handlers created by following the standard way of doing things.
A bit late but I had a similar problem and couldn't find any description of it so thought I'd add it here in case it can help somebody.
No matter what I tried the sorting and paging requests were always duplicated. I tried fixes as described here but even before I had done any type of AJAX update I got the duplication.
I put that problem on hold and after failing to style the pagination to my satisfaction I created my own as a partial view. When deleting the old pagination the duplication was no more..... Haven't taken the time to try and figure out why, just happy it is solved.
So I removed this:
#grid.Pager(mode: WebGridPagerModes.All, firstText: "First", previousText: "Prev", nextText: "Next", lastText: "Last")
As I said, in case it helps someone.
Looks like the paging and sorting links are bound using "on"/"live" event every time the grid is rendered. It could be solved unbinding the events of the elements of the grid before rendering the grid html or on the ajaxUpdateCallback method.
$('#tableDiv').andSelf().unbind();
I have solved this for MVC 5, you would need to use ajax call rather than using the ajax form, catch the ajax response and replace the partial page's DOM generated by the webgrid helper using below:
var data = data.replace('<script type="text/javascript">', '<script type="text/javascript"> $(".table").undelegate();');
$('#YourParentDivIDWherePartialIsRendered').undelegate();
$.ajax
(
{
contentType: "application/json; charset=utf-8",
type: 'POST',
url: '/YourController_Name/YourAction_Name',
data: JSON.stringify(YourModel),
success: function (data) {
//Added to undelegate the old events tagged to the partial view's grid.
var data = data.replace('<script type="text/javascript">', '<script type="text/javascript"> $(".table").undelegate();');
$('#YourParentDivIDWherePartialIsRendered').undelegate();
$('#accountSearch-grid').html(data);
$(document).foundation();
},
error: function (xhr, status, error) {
alert(error);
}
});
put this script to your Index.cshtml or js file
<script type="text/javascript">
(function($) {
$.fn.swhgLoad = function(url, containerId, callback) {
url = url + (url.indexOf('?') == -1 ? '?' : '&') + '__swhg=' + new Date().getTime();
$('<div/>').load(url + ' ' + containerId, function(data, status, xhr) {
$containerId).replaceWith($(this).html());
if (typeof(callback) === 'function') {
callback.apply(this, arguments);
}
});
return this;
}
$(function() {
$('table[data-swhgajax="true"],span[data-swhgajax="true"]').each(function() {
var self = $(this);
var containerId = '#' + self.data('swhgcontainer');
var callback = getFunction(self.data('swhgcallback'));
$(containerId).parent().delegate(containerId + ' a[data-swhglnk="true"]', 'click', function() {
$(containerId).swhgLoad($(this).attr('href'), containerId, callback);
return false;
});
})
});
function getFunction(code, argNames) {
argNames = argNames || [];
var fn = window, parts = (code || "").split(".");
while (fn && parts.length) {
fn = fn[parts.shift()];
}
if (typeof (fn) === "function") {
return fn;
}
argNames.push(code);
return Function.constructor.apply(null, argNames);
}
})(jQuery);
then, processing your grid html string in class
string html = _grid.GetHtml(
columns: _columns,
...
).ToHtmlString();
Regex reg1 = new Regex("<script(.|\n)*?</script>", RegexOptions.IgnoreCase);
string _script = reg1.Match(html).Value.ToString();
html = html.Replace(_script, "");
in the index file:
#MvcHtmlString.Create(#html)
that' all
Actually the solution $('#tableDiv').parent().off('click', '#tableDiva[data-swhglnk="true"]'); is working perfectly but it remains the __swhg in the call URL of pagination so here is the code for removing the extra __swhg in the call of page using AJAX.
$(document).ajaxComplete(function () {
$('a[data-swhglnk="true"]').click(function () {
$(this).attr("href", $(this).attr("href").replace(/(^|&)__swhg=([^&]*)/, ''));
});
});
If anyone is going through these and still having problems, I believe I found the real issue. The script was never being rendered twice on the page for me so the accepted answer didn't make sense.
The issue was instead with this line:
$('table[data-swhgajax="true"],span[data-swhgajax="true"]').each(function() {
If the pager is not in the footer of the table (by defining it in the setup of the webgrid) and is instead defined by calling grid.pager() it will put the pager in a span. This means when the above line is called it binds the click event to the parent of the table (gridContent) and to the parent of the span (gridContent).
There are a few options, but what I opted to do was essentially what top answer said, and remove the delegates for that element like so:
$("#gridContent").off("click", "**");
And then rebind the same exact click function, but only bind it to the span. So the line referenced above I changed to:
$('span[data-swhgajax="true"]').each(function () {
And it works as intended. This will of course break any pagers on the same page that are part of the table.
First Remove ajax Update Callback from Web Grid and add following java script code below to web grid or web grid Container div:
$("#WebgridContainerDiv table a").click(function (event) {
event.preventDefault();
var href = $(this).attr("href");
$.ajax({
url: href,
dataType: 'html',
success: function (data) {
$("#WebgridContainerDiv").empty();
$("#WebgridContainerDiv").html(data);
}
})
});

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.

Can I Use PartialViewResult with PagedList and show it in a PartialView

Hi everyone I have a question, Can I use PagedList in a PartialViewResult Action and show the result in a PartialView?
Here is some code
Controller Code:
public PartialViewResult CargosPorProyecto(string id, int? page)
{
var cargos = db.Cargo.Include(i => i.Proyectos).Where(i => i.NumProyecto.Equals(id)).OrderByDescending(i => i.Fecha);
if (Request.HttpMethod != "GET")
{
page = 1;
}
var pageSize = 10;
var pageNumber = (page ?? 1);
var onePage = cargos.ToPagedList(pageNumber, pageSize);
return PartialView("ListaCargosParcial", ViewBag.OnePage = onePage);
}
In my PartialView i put this code to show the pagination
<div class="pagination-right">
<div class="span12">
<%: Html.PagedListPager((IPagedList)ViewBag.OnePage, page => Url.Action("CargosPorProyecto", new { page = page }), new PagedListRenderOptions { LinkToFirstPageFormat = "<< Primera", LinkToPreviousPageFormat = "< Anterior", LinkToNextPageFormat = "Siguiente >", LinkToLastPageFormat = "Ăšltima >>" })%>
</div>
</div>
And when i load the page that contains the partialview everything looks good, but when i click in Next ("Siguiente") doesn't load in my partial view.
I hope I explained clearly and thanks for the time.
Regards
You could use AJAX if you want to stay on the same page. For example if you are using jQuery you could subscribe to the click event of the pagination links and then trigger an AJAX request to the corresponding controller action and refresh the partial with the results returned:
$(function() {
$('.pagination-right a').click(function() {
$.ajax({
url: this.href,
type: 'GET',
cache: false,
success: function(result) {
// refresh the contents of some container div for the partial
// make sure you use the correct selector here
$('#some_container_for_the_partial').html(result);
}
});
// cancel the default action which is a redirect
return false;
});
});

pass data from view to controller without refreshing the view

i have a script in my view which is:
$('.datepicker').datepicker
(
{ onSelect: function (dateText, inst) {
//pass dateText to my controller
});
</script>
my controller is like this:
public ActionResult Index()
{
string dateSelected = dateText; //read dateText here
if (DateTime.TryParse(dateSelected, out date))
{
date = Convert.ToDateTime(dateSelected);
var reservations = db.Reservations.Where(r => r.Date == date).Include(r => r.Employee).Include(r => r.Room).OrderByDescending(r => r.Date);
return View(reservations);
}
return View();
}
i want dateText to be passed to the controller without the current page being refreshed or reloaded. how to do that?
i tried forms earlier and on the onselect event of the datepicker, i automatically submit the form so the controller can accept it. but i do not want the current page to be refreshed or reloaded.
i just want to pass dateText to the controller without the user noticing the passing.. some sort of $.post i guess but i dont know how to implement it..
UPDATE: here is my try, what is wrong:
ok here is my script:
JSONstring = JSON.stringify(dateText);
$.post("/Home/Index", { jsonData: JSONstring });
here is my controller:
public ActionResult Index(string jsonData)
{
CacheClear();
string dateSelected = jsonData;
.....
//i tried to debug it, but no value of jsonData
}
i want dateText to be passed to the controller without the current
page being refreshed or reloaded. how to do that?
You could use AJAX.
use ajax and send all the variables or data in the ajax data string and provide the url of your controller for example
function add_to_cart(id , title, price,qty){
$.ajax({
type: "POST",
url: "your controller" + id ,
data: "&title=" + title + "&price=" + price +"&quantity=" + qty ,
complete: function(data) {
//alert("Item added to cart");
}
});
}

Resources