CakePHP 3 and partial View update via Ajax - How it should be done? - ajax

One more time I have bumped into the problem how partial view upadtes via ajax should be done in CakePHP3.
From my point of view, there are 3 ways of doing this:
Render required part of the view in dedicated controller action and simply inject the HTML.
Create dedicated template (*.ctp) file for every ajax action, render it like any other action but without the main layout and inject the HTML (kind of variant 1 but with separated VC logic).
Return only required data as an ajax response (eg. entity data) and build part of my view from javascript on client side.
I think that the most efficient solution will be variant 2 because of separation of controller and view logic.
Variant 1 would most probably cause view beeing built twice (on demand, and after request is processed) like in following snipped:
public function ajaxRenderAuditDetails($id = null)
{
if ($id == null) {
return null;
}
if ($this->request->is("ajax")) {
$this->set("result", $this->viewBuilder()->build()->cell("audits", [$id]));
}
}
Variant 3 on the other hand will double the view code in some cases - for example the same html will be genrated in ViewCell as well as on client side javascript
What are the best practices for handling such functionality?

Related

An aesthetic or correct way of invoking an action that requires DOM manipulation as well as controller related tasks in EmberJS

My EmberJS app has a couple of actions (triggered by buttons) that require a view/DOM manipulation as well as setting a state in the controller, followed by a model update. The way I do this, it does not appeal to my programming aesthetics. It gets the job done, but it doesn't look good :(
Here is a gist of how I do things :
<button {{action 'whatever' target='view'}}></button>
App.MyView = Ember.View.extend({
actions:{
whatever:function(){
var ctrl = this.get('controller');
ctrl.set('property',value); // arbitrary example of setting a controller property through it's view
ctrl.controllerMethod(); // invoking a controller method through the view
**// do some DOM manipulation**
}
}
});
Naturally, I can wrap whatever controller related steps I am performing in the view in a controller method and invoke that method through the view, but IMO that's just equally ugly. The view shouldn't really be invoking a controller method like how I have done. Unfortunately, this specific action requires a DOM manipulation as well as setting some state and performing an action in the controller.
I am not sure what is the recommended way of performing this. Can anyone enlighten ?
I suggest you handle the action from the controller. I noticed you're setting a property. You can use that to signal something to the view and then do the DOM manipulation within the view.
App.MyView = Ember.View.extend({
function () {
**// do some DOM manipulation**
}.observe('controller.property');
});
The way I think about it is that UI 'actions' are mapped to a business event (e.g. addClient instead of click), then as a result of that something happens that could change properties of the model, controller. As a result of those changes the view might need to update directly, ideally through a binding, but sometimes is needed to modify the DOM manually.
as #LukeMelia said in his comment you should really handle the changes in your controller and update your view (if you need to?) via databinding.
so, you would just omitt the target="view" argument from your view helper and Ember will look for the proper action in the nearest controller, bubbling all the way up to the route, and so on.
a simple code snippet (with what you provided in your first post) would look like:
Handlebars Template:
<button {{action someAction}}>Fire!</button>
Ember.Controller:
App.MyController = Ember.ObjectController.extend({
myProperty: 'cool',
printMyCoolness: function () {
console.log("I'm using Ember.js!");
},
actions: {
someAction: function () {
this.set('myProperty', 'set on fire!');
this.printMyCoolness();
}
}
});

What is the difference between view & partial view in mvc

i am learning mvc. so like to know what is the difference between view & partial view in mvc in terms of functionality.
normal view & partial view both render html in page....so what is the difference and limitation for two?
what are things are accomplish by partial view. please give me few scenario where people need to use partial view.
here is posting two code to load view based on dropdown value change.
$(function() {
$('#myddl').change(function() {
var url = $(this).data('url');
var value = $(this).val();
$('#result').load(url, { value: value })
});
});
public ActionResult Foo(string value)
{
SomeModel model = ...
return PartialView(model);
}
public ActionResult GetView(int id)
{
switch (id)
{
case 1:
return View("View1", model1);
break;
case 2:
return View("View2", model2);
break;
default:
return View("Default", modelDefault);
}
}
now see one action result return PartialView and another return just view to ajax method. which approach is right? when second approach need to use?
please guide me with knowledge. thanks
We use partial view to render a specific section of a page, like take an example of Customer. Your Index view of Customer controller will be a normal view while your grid of customers will be a partial view so that when you update or insert a new customer or delete a customer you will just render your partial view which contains grid of customers not the whole index view.
As far as i know, a partial is used as part of a view and can be shared across multiple views to provide extra functionality for those views. Also, views can be broken down to partials to make editing easier and eliminate redundancy. Hope it helps a little
Partial view kept to use as partial page of the main page(parent page).
What does mean of partial view? Actually in the main page we will have all the HTML page attributes as below:
html lang="en"
head
title
meta
body
But in partial view we will not have all above attributes.
Find the features of partial page:
1. Partial page will be light wait and get fitted into the any view.
2. This will use as the reusable component.
3. Partial view will be render inside of a View(parent view or page).
For all who coming from ASP.Net background they can understand partial view as user control.
Thanks
Afazal
mdafazal#gmail.com

How to change WebGrid action for getting data (.NET MVC3)

I have a Partial View that renders WebGrid. My controller looks like
public ActionResult Index()
{
return View();
}
public ActionResult GetUserList(int? page, string sort, string sortdir)
{
var model = UserModel.getList(page,sort,sortdir);
return PartialView("_UserList",model);
}
Index.cshtml :
....
#Html.Action("GetUserList")
The problem is that every time I click on grid navigation or sort links it calls Index method. How can I make Webgrid to execute a different action (GetUserList in this case)? I'm sure I can prepend GetUserList to all links in grid using jquery, but I believe it should be a better way.
It's also possible that what I'm doing is completely wrong, so thanks for your suggestions.
After lot of monkeying around and digging (and even fiddling with Reflector with WebGrid's source code), I came to the conclusion that with WebGrid, you cannot control/change the Header link action.
To create the header link URL, the path is taken from HttpContext.Request.Path, so there is no way to customize it to point to a different route.
One very ugly hack would be to tap into to jQuery Ajax's events (since the header link uses jQuery.load to sort) and overwrite the URL:
Album Id
Better solution would be to use:
Telerik Grid which lets you specify custom routes and also offers much more flexibility in rendering your layout
or MvcContrib Grid (not sure if this lets you modify header links but definitely offers more flexibility than WebGrid)
#MrChief had the idea above about the ugly hack...I put that together. Here is the main code that I used to do this. It does, indeed, hijack the ajax call before it is put on the wire. The key is to modify the URL that is getting sent because the grid will grab that URL from HttpContext.Request.Path. and plug it into the onclick for the anchor element.
I put this into my main common.js and will simply attach a function to capture the ajaxSend event which happens just before the data is sent.
// Used to hijack the sending of all AJAX calls. Before it sends the call to the server, it checks to see if the
// active element (the element that prompted the call) is marked with a given class. If so, then it will perform
// the given operation.
$(document).ajaxSend(function (event, jqXHR, ajaxOptions) {
var activeElement = document.activeElement;
if ($(activeElement).attr('redosorturl') != null) {
// If this is a sort anchor link from a grid that needs to have the sort link redone, do it here.
// the code is in the eipGrip.js file.
if ($(activeElement).attr('redosorturl').toString() == 'redoSortURL') {
var newURL = RedoGridSortURL(activeElement, ajaxOptions.url.toString());
ajaxOptions.url = newURL.toString();
}
}
return false;
});
When rendering the page, I have marked the tag in column header that contains the incorrect URL with a class named "redosorturl', so I know when I hijack the ajax call, the operation has to be done on this element. I then call a custom function that gives me the correct URL, then the ajaxOptions.url is then rewritten with that new URL.
I have to pass the activeElement to that rewrite function so I can traverse up the DOM to get the grid information, where I have put data like the controller and action method that is used along with and IDs and other info that I use for the URL. Likewise, I pass in the current url string because the grid will inject a token at the end of the url that I parse off and put on the new url.
Your conclusion isn't right. You just need to wrap your webgrid in a Get form:
using (Html.BeginForm("GetUserList", "ThingaMaBob", System.Web.Mvc.FormMethod.Get))
{
var grid = new WebGrid(
...
));
Html.Hidden(grid.SortFieldName, grid.SortColumn);
Html.Hidden(grid.SortDirectionFieldName, grid.SortDirection == SortDirection.Ascending ? "ASC" : "DESC");
}
The hiddens are so that the sort dir and sort field end up in parseable form in the querystring. You end up with urls like localhost/ThingaMaBob/GetUserList?someotherfields=whatever=&sort=city&sortdir=ASC
If you remove [HttpPost] attribute and let the route come to the same function. you'll find the Request["page"] value in your method. this will allow you to put a check on Request["Page"] value.

Using fancybox - how can I tell if an HTTP request is AJAX or not?

I'm using fancybox plugin to load a page and execute some code. The problem is that at times theres always the chance that someone would click on a link thats meant to be opened in a fancybox window before the page loads completely and the fancybox plugin is set up opening the page looking messed up in an complete browser window. Is there a way to tell whether an HTTP request is via ajax or not so I can set up my layouts accordingly.
I'm using the zend framework and have defined two layouts one for pages opened with fancybox and one is the regular page layout.
In you actions you can use isXmlHttpRequest() method to detect ajax request. For example, you could do:
public function onlyajaxAction() {
if ($this->getRequest()->isXmlHttpRequest()) {
// handel ajax request.
} else {
// if not an ajax request, e.g. throw an exception or whatever
}
}
You can check the X-Requested-With header, which is set to XMLHttpRequest by many Javascript libraries.
If you need to use a same action in different context to provide the according result, you may use the contextSwitcher() action helper (or ajaxContext())
<?php
class YourController extends Zend_Controller_Action
{
public function init ()
{
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('do-something', 'json')
->initContext();
}
public function doSomethingAction ()
{
// some logic here
$this->view->data = $data;
}
}
Use the ?format=json parameter to switch context, in case of JSON ZF will take care to convert $this->view->data to JSON for you, it will also disable layout, etc.

How do you handle displaying navigation and sub navigation in an MVC app?

I'm having trouble determining where to place navigation for an MVC app. For example, say you have the following structure:
Conferences
South Eastern Conference
Florida Gators
Georgia Bulldogs
Arkansas Razorbacks
Pac-10
USC
Hawaii
Big East etc...
How would you best create a structure for implementing a 'main' navigation and subsequent 'sub' navigation? Using the hypothetical example, You'd have specific sub navigation for each conference, showing its respective colleges (and only that conferences colleges).
Is this something you'd handle in the main view and just hide the non-selected conference?
Or would you create a menu helper (or yet another partial) and call that from each individual college's view?
Best way is to use multiple, nested master pages. e.g. Site.master would contain your top-level nav (list of conferences?) then you'd have a different master page for each conference that would 'extend' site.master. You can, in theory, have as many nested master pages as you want. Finally, Florida Gators etc would be 'real' views (i.e. non-master pages).
The tricky part is telling any parent master page which navigation item is currently selected. Because you can't bind master pages to the ViewModel you'll have to use the View Dictionary e.g. View["SelectedMainNavItem"].
Why not use some global layout template that always displays the main navigation, and relies on some helper to render the subnav? (The helper may be superfluous -- you might just output the subnavigation inline in the layout template)
Your controller passes current category/sub-category, and some data structure describing the current subnavigation options, to the view.
After contemplating this issue for a while along with the suggestions, I came up with this solution. Since my subnavigation will always be below the main navigation, I decided to go with the Convention over Configuration method.
In my Site.Master, I have the following two render partials. One displays the main navigation and the other makes a call to BuildSubNavigation to display get the name of a partial to render:
<% Html.RenderPartial("_MainNavigation"); %>
<% var submenu = ViewContext.BuildSubNavigation();
if (submenu != null) {
Html.RenderPartial(submenu);
}%>
Granted, this could be thrown into a Helper, and I intend to do that, this is more explicit and aids in the understanding of the issue.
What this does is call the BuildSubNavigation method. It goes with the convention that if a controller is to have a specific sub navigation, there will be a partial in the form of "_Navigation" So in the spirit of the example, one partial would be "_SouthEasternConferenceNavigation" What I do is then check to see if the current view actually exists. If it does, I return the name, where it's then used to render the partial.
public static string BuildSubNavigation(this ViewContext vc) {
var controller = vc.RouteData.Values["controller"] ?? "";
var viewName = "_" + controller + "Navigation";
if (ViewExists(vc.Controller.ControllerContext, viewName, null)) {
return viewName;
} else {
return null;
}
}
And this is the method that checks whether the View actually exists against the current View Engine:
public static bool ViewExists(ControllerContext cc, string viewName, string masterName) {
if (ViewEngines.Engines.FindView(cc, viewName, masterName).View != null) {
return true;
} else { return false; }
}
I'm unsure if this is the best way to do this, but it's working rather well for a small project I'm currently working on.
Thanks for the answers!

Resources