There is an issue I am facing in using pagination widget with ajax. What I am doing is, that I select category and then hit an ajax request to fetch the corresponding list by loading the data in the template and returning the html like this:
<f:if condition="{articles}">
<f:then>
<f:widget.paginate objects="{articles}" as="paginatedArticles" configuration="{itemsPerPage: numberOfRecords}">
<f:for each="{paginatedArticles}" as="article">
<h2>
<f:link.action action="show" arguments="{article : article}"> {article.title}</f:link.action>
</h2>
<p>
<f:format.html>{article.description}</f:format.html>
</p>
<hr/>
</f:for>
</f:widget.paginate>
</f:then>
<f:else>
No Records Found
</f:else>
And in my controller in my ajaxMethod I am simply doing
$this->view->assign('articles', $result); so it loads up the template with my result.
But now after rendering the ajax, if I use the pagination, the view breaks. There is no styling or header or anything.
This is how it shows up when I click the next on paginate widget: http://prntscr.com/kr8vg0
Just for completeness, here is the setup.txt which I have written that calls the ajax.
// PAGE object for Ajax call:
tt_content.list.20 = CASE
tt_content.list.20 {
key.field = list_type
}
ajax = PAGE
ajax {
typeNum = 1272
config {
disableAllHeaderCode = 1
disablePrefixComment = 1
additionalHeaders {
1526302502.header = Content-Type: text/html;charset=utf-8
}
}
10 = CONTENT
10 {
table = tt_content
select {
pidInList = this
orderBy = sorting
where = (list_type IN ("articleext_list"))
}
renderObj = < tt_content.list.20
}
}
Any help would be appreciated.
The typeNum that drives (should drive) XHR requests from widgets, is added from within the Fluid extension and does not require you to add a special PAGE object.
Even if you somehow made overrides that call your specific controller action it may not be treated correctly. Usually you would never refer to a content element instance but rather a straight Extbase request bootstrapping. Among other things, because rendering the content object adds wrappers.
So you should remove this and make sure you pass a QueryResult to the pagination widget. Then override the widget template if necessary. The rest should work without having to configure TS.
EDIT:
The pagination widget itself being used in a template that is rendered via XHR means it transfers the arguments you use to load the XHR - including the custom typeNum value. The widget then creates standard links that your click like normal - and they will be a link to the "inner content" of your XHR response because the URL contains a type number.
Here's where it gets bad: you cannot remove this typeNum once it is added. So you will have to instead cause the next/prev etc. links that are clicked, to cause a new XHR request that loads the content (how you do that very much depends on your JS application so can't guide you there).
My comment about ensuring a QueryResult is not relevant unless your pages don't change and you for example always see items 1-10.
But in order to solve this I would actually recommend that you do not use the pagination widget. The main reason being you're already in an XHR context that allows you to receive arguments for your controller action and manipulate the offset and limit parts of the query from within your controller action. That means you can generate your links not to the widget but to the controller action, and for example put a CSS class on the links that should trigger XHR requests vs. those that should reload the entire page (for example to show a detail view). You avoid having to override the pagination template and you control all parameters of all links.
In fact, I would favor a controller argument for offset above using the pagination widget regardless of XHR or not. There's a long list of technical reasons why that I won't list here but suffice it to say, trading a lot of "black box" for having to create a single argument is a very reasonable and predictable-result thing to do.
Related
I'm sure this is simple but I'm struggling to find it
Inside a controller you can do something like this:
public ActionResult MyAction()
{
string url = Url.Action(action, controller),
// do something with the url
}
What's the Ajax equivalent? i.e. where you would call Ajax.ActionLink in a View whats the equivalent for the controller?
Elaboration-
I have a master/detail arrangement with a grid and some input elements. You can click on select/delete in the grid to amend or delete the line.
The grid is a Kendo UI grid, the view is rendered via:
a partial view to render the input elements
creating a json object, i.e.
#{
var jsLines = #Html.Raw(Json.Encode(Model.Lines));
}
Binding the Kendo grid to this json
From within the grid I want to hit on select and call an Ajax method to update the partial view with the form details
thanks
You can use Url.Action from the razor view. Something like :
$.ajax({
url: '#Url.Action("Action", "Controller")',
...
I'm not at all convinced that this is the right way to go but it's always good to have options.
Ajax.ActionLink seems to be the same as Url.Action but with a few attributes thrown in. So you can use this:
return string.Format("<a data-ajax='true' data-ajax-mode='replace'
data-ajax-update='{2}' href=\"{0}\">{1}</a>",
Url.Action(action, controller, routeValues),
text,
"formContainerSelectSection");
to update this:
<div id="formContainerSelectSection">
... stuff to be replaced via ajax
</div>
I accept, especially after the discussion with NicoD, that there are other and probably easier ways to do this, in particular this is creating a link in the controller, that's the Views job, but the original question was about how to do this
I have a section of a form that dynamically loads different sets of fields based on the user's selection in a control. I'm using a javascript event handler to detect when the selection changes, and using AJAX (with HTML payload) to pull in the proper set of fields.
I would like to be able to use Laravel's Form::getValueAttribute() method to automatically fill in the form fields' values in both the static and dynamic form parts. However, the partial view that is loaded by my AJAX call does not have the same instance of the Form class as the view with my main Form, so I can't simply call getValueAttribute() in the partial.
My thought is to make the AJAX call a POST, and serialize the necessary data (a subset of Input::old() or the model data depending whether the page is loaded as the result of validation errors, or an UPDATE request) to send along with the POST so that the HTML fragment I get back has the values set properly.
Is this the best way to get what I want? If so, does Laravel have any tools to help with the serialization of form data? If not, what might be a better approach?
I've found an approach I like better. When the view is loaded normally I use AJAX as usual to load the partial. But when the view is loaded for a validation post-back or for editing, I use Laravel's Views' nest method to nest the partial view containing the proper fields directly into the response. The partial then has access to all the Input and error data I need. The user is still able to change the field set as usual but I put up a confirm prompt for them if they have already set some values in a field set they previously selected. If they decide to proceed anyway, the field set is cleared and a new field set is brought in via AJAX as usual.
My code looks something like this:
Controller:
public function newThing() {
if ( Request::session()->has('errors') ) {
// this is a validation post-back
return View::make('thing')
->nest('fields', 'fields_partial');
} else {
// just a normal unfilled form
return View::make('thing');
}
}
public function editThing() {
return View::make('thing')
->nest('fields', 'fields_partial');
}
View: thing.blade.php (just a snip of it)
...
<form>
...
<select id="picker">...</select>
<div class="sub-fields">
{{ isset($fields) ? $fields : '' }}
</div>
...
</form>
...
<script>
$('#picker').change(function() {
// if any .sub-fields inputs have been changed, get confirmation from the user
// if user confirms, do ajax stuff to replace .sub-fields contents with new field set
// otherwise cancel the change
});
</script>
Inside a component's view, I have something like this:
<?php echo TestcompHelperFind::loadStates(...); ?>
<?php echo TestcompHelperFind::loadCounties(...); ?>
The above static functions load <select> dropdowns with the state names and countries respectively.
The class TestcompHelperFind is located in the file /administrator/components/com_testcomp/helpers/find.php.
How do I load States dropdown list based on the country selected using AJAX? I'm not sure what url I should provide in the ajax function.
On the client, you will need a function that watches the country select for changes, and when it happens calls the appropriate url with a callback that will populate the counties select.
On the server, you need to output the select content.
Since you have the html output already working, let's use this approach. As an alternative you could have your server method return a json object and use the javascript to parse it and populate the select. But let's stick to html communication, i.e. the server returns the html contents of the select.
1. On the server
1.a. Output the counties select
We only need to return the result of the TestcompHelperFind::loadCounties(...); to the ajax call. This is achieved easily writing a new method in the component's controller, i.e. the controller.php in the root of the component folder or one of the sub-controllers if appropriate. It's up to you to place it in a meaningful spot.
Inside the controller simply add a new public task such as
class SomethingController extends JController
{
public function getCountiesHTML() {
$input = JFactory::getApplication()->input;
$country = $input->getCMD('filter_country');
// load helper if necessary, then:
echo TestcompHelperFind::loadCounties($country);
exit; // this will stop Joomla processing, and not output template modules etc.
}
Please note the exit; at the end, this will make Joomla output only the component's output (our echo) and not the whole template/modules etc.
1.b Add an ID to the country and county selects so that it will be possible to manipulate them on the client; I'll assume filter_country and filter_county ;
2. On the client
you will want to invoke the url
index.php?option=com_something&action=getCountiesHTML&filter_country=UK
when the country select is changed. It will also need to cancel any pending requests to avoid overlapping messages. To keep things simple, let's assume you use a library to handle Ajax, I'll write an example for jQuery:
<script>
var xhr;
jQuery(function($) {
$('#filter_country').change(function(){
var filterCountry = $('#filter_country').val();
if (xhr && xhr.abort) {xhr.abort();xhr=false;}
xhr = jQuery.ajax(
url: 'index.php',
data: 'option=com_something&task=getCountiesHTML&filter_country='+filterCountry,
success: function(data){
jQuery('#filter_county').replaceWith(data);
}
);
});
});
</script>
For cancelling the previous request, please see a dedicated answer such as this one.
I am trying to load json data from web2py controller to jQuery dataTable via AJAX.
But only blank dataTable is rendered (with desired formatting, search box, etc.)
Can somebody pl. point out into my code as to where I have a mistake.
Data is not displayed (as returned by "get_data" method).
I have made sure that the database tables have been populated.
Controller
def show_data():
return dict()
def get_data():
custdata = db.executesql(qry, as_dict=True)
return custdata
For testing purpose, I returned response.json(custdata) in a separate method & validated the same on "jsonlint.com".
It is valid json.
View (show_data.html)
{{extend 'layout.html'}}
$(document).ready(function() {
var oTable = $('.smarttable').dataTable( {
"sScrollY": "200px",
"sAjaxSource": "{{=URL('MIS','get_data.json')}}",
"sDom": "frtiS",
"bDeferRender": true
} );
} );
Lastly, html table tags are defined for a table with class="smarttable"
Your get_data function should return a dictionary, like this:
def get_data():
custdata = db.executesql(qry, as_dict=True)
return dict(data=custdata)
In web2py, a view is only called if the controller action returns a dictionary -- otherwise, the controller output is simply returned to the client as is (and as is, custdata has not yet been converted to JSON).
When you call the URL /MIS/get_data.json, the .json extension tells web2py to look for a /views/MIS/get_data.json view file to use for rendering the JSON. If it doesn't find that view file, it will trying using /views/generic.json, though it will only use generic.json for local requests, unless you override that by specifying response.generic_patterns=['json'].
As an alternative to using a view to render the JSON, you could also do:
def get_data():
custdata = db.executesql(qry, as_dict=True)
return response.json(custdata)
EDIT: The jQuery DataTables plugin requires the JSON to include some special parameters, so you'll have to add those before returning the JSON. To make things easier, you might consider using PowerTable (a web2py plugin for DataTables), or the jqGrid widget included with web2py's plugin_wiki (the widget can be used on any web page, not just wiki pages).
you have to have the "key" values in the "dictionary" that you give for return .
iTotalRecords,iTotalDisplayRecords,sEcho and aaData. you can find the explanations in http://datatables.net/usage/server-side
I want to build a webapplication with a "Single Page Interface", using ASP.NET MVC.
I have searched if this was at least possible and I think the answer is: not by simple means (reading http://msdn.microsoft.com/en-us/magazine/cc507641.aspx#S2 second-last paragraph; that article is from May 2008, though).
I found other examples which implemented this by coding/hacking with jQuery. However, I'm looking for a clean solution, using standard .NET approaches, if possible.
What I want is precisely the same functionality when you create a new "MVC Web Application". However, instead of links to "/Home/About" which reloads the entire page, I want links to "#Home/About" which loads only the new part via AJAX.
The standard approach of calling templates (partial views) with Html.RenderPartial is exactly what I want, only then loading them in through AJAX-requests.
Of course, it might be that I can't use these templates that are rendered by the Master-page for some reason (maybe it's expecting to always be called in a certain context from a certain place or so). But maybe there's another clean solution for how to build your template-pages and fetching them from the Master-page.
Who has a nice solution for implementing such thing, a Single Page Interface?
PS: I'm developing in Visual Web Developer 2008 Express Edition with MVC 1.0 installed, in C#
[edit]
Below I read that working with the templates is possible and that jQuery looks indeed like inevitable, so I tested it.
The following code transforms regular links created by Html.ActionLink into anchor-links (with #) to contain history, and then fetch the page via AJAX and only injecting the html-part I'm interested in (i.e. the partial page inside div#partialView):
$("a").each(function() {
$(this).click(function() {
$("div#partialView").load($(this).attr("href") + " div#partialView");
location.hash = $(this).attr("href");
return false;
});
});
These links also allow for graceful degredation.
But what I have left now, is still fetching the whole page instead of only the partial page. Altering the controller didn't help; it still provided me html of the whole page, with all of these statements:
public ActionResult About()
{
return View();
return View("About");
return PartialView();
return PartialView("About");
}
How could I only return the content of the part I'm interested in (i.e. the contents of Home/About.aspx)?
What I'd like is POSTing a value with AJAX (e.g. "requesttype=ajax") so that my controller knows the page is fetched via AJAX and only returns the partial page; otherwise it will return the whole page (i.e. when you visit /Home/About instead of #Home/About).
Is a good practice to alter Global.asax.cs maybe, to create a new routing schema for AJAX-calls, which will only return partial pages? (I haven't looked into this much, yet.)
[edit2]
Robert Koritnik was right: I also needed an About.ascx page (UserControl) with only the small HTML-content of that page. The first line of About.aspx was linked with the Master-page via MasterPageFile="~/..../Site.master" which caused that all HTML was printed.
But to be able to execute the following in my controller:
public ActionResult About()
{
return Request.IsAjaxRequest() ? (ActionResult)PartialView() : View();
}
I needed to alter the way a PartialView (.ascx file) and a View (.aspx) file was found, otherwise both methods would return the same page (About.aspx, ultimately resulting in an infinite loop).
After putting the following in Global.asax.cs, the correct pages will be returned with PartialView() and View():
protected void Application_Start()
{
foreach (WebFormViewEngine engine in ViewEngines.Engines.Where(c => c is WebFormViewEngine))
{
/* Normal search order:
new string[] { "~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx"
"~/Views/Shared/{0}.ascx"
};
*/
// PartialViews match with .ascx files
engine.PartialViewLocationFormats = new string[] { "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.ascx" };
// Views match with .aspx files
engine.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx" };
}
RegisterRoutes(RouteTable.Routes);
}
Full view vs. Partial view
Seems like you've messed up something. If you create an About.aspx page with all the HTML needed to display the whole page it doesn't really matter if you say
return PartialView('About');
The view still returns all the HTML that's written in it.
You should create a separate About.ascx that will only have the content of the page itself without the header and other stuff that's part of the whole page.
Your original page About.aspx will have something like this in its content (to avoid repeating writing the same content twice):
<%= Html.RenderPartial("About") %>
And you can have two controller actions. One that returns a regular view and one that returns a partial view:
return View("About"); // returns About.aspx that holds the content of the About.ascx as well
return PartialView("About"); // only returns the partial About.ascx
Regarding routes in Global.asax
Instead of writing separate routes for Ajax calls you'd rather write an action filter that will work similar as AcceptVerbsAttribute action filter. This way your requests from the client would stay the same (and thus preventing the user from manually requesting wrong stuff), but depending on the request type the correct controller action will get executed.
Well, you can load Partial View through AJAX request. In example, I'll use jquery to make an ajax call.
These could be the action in controller (named HomeController):
public ActionResult About()
{
//Do some logic...
//AboutView is the name of your partial view
return View("AboutView");
}
JQuery ajax call to place the retured html in place you want:
var resultDiv = $('#contentDIV');
$.ajax({
type: "POST",
url: "/Home/About",
success: function(responseHTML) {
resultDiv.replaceWith(responseHTML);
}
});
[edit-question is updated]
It is possible to do exactly what you want. First controller action can give you back the partial view, so mine "AboutView" could have been something like this:
<table>
<tr>
<th>
Column1Header
</th>
<th>
Column2Header
</th>
</tr>
<tr>
<td>
...
</td>
<td>
...
</td>
</tr>
and this HTML is exactly what are you going to have in responseHTML on success handler in jquery ajax method.
Second, you can distinguish in controller action if the request is an ajax request:
public ActionResult About()
{
//partial AboutView is returned if request is ajax
if (Request.IsAjaxRequest())
return View("AboutView");
else //else it will be the default view (page) for this action: "About"
return View();
}
We've got a site that does exactly this, and you really want to use the jQuery route here--alot easier to implement in the long run. And you can easily make it gracefully degrade for users who don't have javascript enabled--like google.
it isn't all that clear what are you asking for, is it for a complete example or for some specific functionality? You should be able to do this without JQuery for simple scenarios, you can use the Ajax view helpers like the ActionLink method. Also, I don't really understand what is your issue with RenderPartial, but maybe you're looking for something like RenderAction from ASP.NET MVC Futures.
ASP.NET MVC 4 (now in beta) adds support for Single Page Applications in MVC.
http://www.asp.net/single-page-application
UPDATE:
...and they removed it from the MVC 4 RC
UPDATE:
...and it is back with the 2012 Fall update