How do i set up ajax in cakephp without using the default ajax helper? The default ajax helper puts the js code on the page itself, I don't want that. I want it to be set in a seperate js file (ie general.js) instead. How do i do that? I have pagination already set up.
First make sure you have jquery set up. In your default.ctp (View/Layouts/default.ctp) add the following line within the <head> section:
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
In your AppController.php file (Controller/AppController.php) add the following lines
function beforeRender() {
if ($this->request->is('ajax')) {
$this->layout = false;
}
}
This causes the behaviour that when an ajax call is made to an controller action only the view itself is loaded rather than the whole layout.
In your general.js file (webroot/js/general.js) add the following code:
$(document).ready(function(){
ajaxPagingNavigation();
});
function ajaxPagingNavigation() {
$(".paging a").click(function(e) {
$.ajax({
url: $(this).attr('href'),
cache: false
}).done(function( html ) {
$("#content").html(html);
ajaxPagingNavigation();
});
e.preventDefault();
});
}
Related
I am new to CakePHP. I have installed CakePHP 3.2.10.
I have implemented simple AJAX calls. I have also implemented pagination in normal view.
Now I want to show records, loading with AJAX and using pagination.
Can anyone guide me how to go about doing this?
I have referred to the cookbook but did not get proper information.
Do I create a normal action and view with pagination code ?
Simply, you can use liveQuery Javascript library. you can download from here
And add this library code in your CakePHP template layout in
Wrap your listings and pagination links in div tag apply id="wrapper".
add this function in common javascript code which must be load in
page end before end of body tag
Add Below Code in Javascript
function ajaxPageLoader(request_url) {
console.log("Content loading from : "+request_url);
$("#wrapper").load(request_url + " #wrapper", function() {
window.history.pushState({}, "", request_url);
console.log("Content loaded");
});
}
$(document).ready(function(){
$('your_pagination_link_selector').livequery(function() {
$(this).unbind('click').bind('click', function(e) {
e.preventDefault();
ajaxPageLoader($(this).attr('href'));
return false;
})
});
});
I am creating controller in Code Igniter and make form in ExtJs 4.2.1 now from where i call control and how?
i used url property of form and put controller name there but nothing happen
Update
I think i am not clearing my question actually i want to post data through submit function in which i pass data to php file in my server side i use Code Igniter Rest Api so here i want pass data to specific controller
ExtJs is a javascript framework and is executed on the client side. It has its own MCV system.
It makes no sense to mix up a php controller with a javascript view.
Be sure to read the introduction to MVC in ExtJS.
Also in ExtJS you don't call the controller. On initialisation of the app, all controllers get lloaded. In the controller you define what it has to control, and from then on the magic hhappens: The events defined in the controller are fired whenever needed.
In ExtJS 3.3.1
In login form put the buttons and call function submit_login();
buttons: [{
text: 'Login',
handler: function() {
submit_login();
}
}]
Submit_login() code is, I used Ext.Ajax.request to submit login parameters
You can debug the message with alert(response.responseText):
function submit_login() {var useridx = Ext.getCmp('useridx').getValue();var userpasswordx = Ext.getCmp('userpasswordx').getValue();Ext.Ajax.request({url:'".$url."', method:'POST',
params :{useridx:useridx,userpasswordx:userpasswordx},
success:function(response){
//alert(response.responseText);
//return;
var jsonData = Ext.util.JSON.decode(response.responseText);
var resultMessage = jsonData.Message;
var isLogin = jsonData.isLogin;
if (isLogin)
{
window.location = '';
}
else
{
Ext.Msg.alert('Info',resultMessage);
}
},
failure: function(){
Ext.Msg.alert('Not OK');
}
});
}
variable $url is:
$url = "index.php/apps/login";
You can create Apps controller
and create function login
public function login()
{
$this->load->view('login');
}
Create login.php in view
if ($i==1) {
//session_start();
$this->session->set_userdata('userid',$useridx); echo '{"success" : true, "isLogin": true,"Message" : "User Successfully Login"}';
} else {
echo '{"success" : true, "isLogin": false, "Message" : "Salah User: '.$useridx.' dan Password "}';
}
You also do this in Ext JS 4.2.1 with same code.
This is works for me
Andrex Maulana
I create a function in CakePHP controller class to process AJAX request. But I found different result when using CakePHP function and simple (Non-MVC) PHP code. My problem is when it goes to submit() process. When using CakePHP function it returns blank page.
Here is the AJAX request code that I use:
var userdata = {username : $("#UserUsername").val()};
$.ajax({
type:'POST',
url: 'http://localhost/mycakephp/users/login',
data: userdata,
success: function(data){
if(data==0){
alert("empty");
} else {
$("#UserLoginForm").submit();
}
}
});
But when I pointed the url to external site like this:
url: 'http://localhost/test/test.php'
Which test.php is a simple PHP code to handle request, submit process works fine.
Sorry, but your code looks bizarre to me: There you have a login form, you send using ajax your username calling the Controller "UsersController" / function "login", and when you have an answer from this function, then you submit again another form ("#UserLoginForm") and send it again to the controller? You are sending two forms! Most probably this is not what you want. Correct me if I am wrong.
I guess what you want is just submit the UserLoginForm and wait for an answer, whatever it is OK or NotOK, and finally show this result.
You have two options to do this: either CakePHP way or your own ajax code using JQuery. I like to use both, depending on the user experience I want to get.
1. CakePHP way
Include JS Helper in the controler using the public $helpers = array('Js'); and then create a Form in the view, using the submit from the JsHelper.
View
<?php
echo $this->Form->create();
echo $this->Form->input('username');
echo $this->Form->input('whatever');
// use the Js submit from JsHelper
echo $this->Js->submit('Send', array(
'url'=> array('controller' => 'users', 'action' => 'login'),
'update' => '#update_ajax_div',
));
echo $this->Form->end();
// Next line is actually very important in order
// to print the automatically created ajax code from JsHelper.
echo $this->Js->writeBuffer();
?>
<div id="update_ajax_div">
this will be overwritten after submit.
</div>
Controller
In the controller all the data in the form will be sent in the $this->data[] array. For example $this->data['Users'] if this is the Model being used in the Form->create().
The code is pretty standard, except the layout, which must be set to ajax.
public function login(){
// print the data being sent
$dataFromAjaxLink = $this->data[];
$v = var_export($dataFromAjaxLink, true);
$this->log("Ajax log: ".$v, 'debug');
if(isset($this->data['User'])){
$user_name = $this->data['User']['username'];
...
// do your stuff
}
// the answer must be ajax layout
$this->layout = "ajax";
// I like to use elements when using ajax, it keeps the folders clean
// in this example /app/View/Elements/display_ajax_result.ctp
$this->render('/elements/display_ajax_result');
}
The content of this element will be printed in the div "update_ajax_div"
2. Pure Ajax way
The second version is done by manually typing ajax code in <script> tags. This solution gives you more freedom, allowing you to do more complex stuff, but the code is not so clean!
The following JQuery code must be inside some button/div/whatever event...
$(document).ready(function(){
$(".someButton").click(function() {
// create the json data to be sent
var username = $(....).val();
var dataString = ...
// call ajax
$.ajax({
type: "POST",
// never type full paths as in your example. They are sources of errors!
url: "<?php echo $this->Html->url(array(
"controller" => "users",
"action" => "login")); ?>,
data: dataString,
cache: false,
success: function(html){
$("#update_ajax_div").html(html);
}
});
...
The controller is the same as the CakePHP way. Remember to add ajax layout.
I hope it helps you.
According to your comment, if you use the SecurityComponent, you could disable POST validation on the login action. In your UsersController, add this:
function beforeFilter()
{
parent :: beforeFilter();
switch($this->request->params['action'])
{
case 'login':
$this->Security->validatePost = false;
$this->Security->csrfCheck = false;
break;
}
}
But off course you loose the value added by the SecurityComponent on the login action.
Has anyone found a way to intercept the default Form::postLink() forms with Jquery?
I would like the form to work without JS (therefore the postLink).
But with JS enabled I want to intercept the post and call it via AJAX.
<?php echo $this->Form->postLink('Delete', array('action'=>'delete', $prospect['Prospect']['id']), array('class'=>'postLink', 'escape'=>false), __('Sure you want to delete # %s?', $prospect['Prospect']['id'])); ?>
generates:
<form action="/admin/prospects/delete/4f61ce95-2b6c-4009-9b89-07e852b0caef" name="post_4f648f773923b" id="post_4f648f773923b" style="display:none;" method="post">
<input type="hidden" name="_method" value="POST"/>
</form>
<a href="#" class="postLink" onclick="if (confirm('Sure you want to delete # 4f61ce95-2b6c-4009-9b89-07e852b0caef?')) { document.post_4f648f773923b.submit(); } event.returnValue = false; return false;">
Delete
</a>
The main problem is that the js is placed inline here. Therefore always triggers even if I try to intercept the click event (or the post event - tried that too):
<script>
$(document).ready(function() {
$('table.list a.postLink').click(function(e) {
e.preventDefault();
alert('Handler for .submit() called.');
// TODO: do ajax request here and return false
return false;
});
});
</script>
So in the end the form always submits normally and redirects - either ignoring any ajax call (catching the form submit) or posting/redirecting regardless of an ajax call just made (catching the click event).
I would like to delete this record via AJAX and - if successful - just remove that table row from DOM. It would be great if one doesn't have to modify all 300+ "delete buttons" in the application for it, though.
If everything fails I could probably still override the FormHelper (extend it and alias it). But I was hoping on a less invasive solution here.
I know this is old, but for any of those searching:
You need to first remove the 'onclick' attribute added to the delete
link.
Then, you add a .click function to the delete link
You need the url (which can be hardcoded or retrieved from the form, which is always the prev element in cakephp Form->postLink
Here is the code:
$(function(){
$('a:contains("Delete")').removeAttr('onclick');
$('a:contains("Delete")').click(function(e){
e.preventDefault();
var form = $(this).prev();
url = $(form).attr("action");
$.post(url);
return false;
});
});
jymboche - what a genius
why didnt i think of it myself?
Well, here is the modified answer of yours:
$(document).ready(function() {
$('table.list a.postLink').removeAttr('onclick');
$('table.list a.postLink').click(function(e) {
e.preventDefault();
if (!confirm('<?php echo __('Sure?')?>')) {
return false;
}
var form = $(this).prev();
var url = $(form).attr("action");
var tr = $(this).closest('tr');
url = url + '.json';
$.post(url).success(function(res) {
if (res.error) {
alert(res.error);
return false;
}
tr.fadeOut(200);
}).error(function() {
alert("Error");
})
return false;
});
});
This is for future reference only.
I will still accept your answer as you gave me the right idea.
jymboche's solution helped me to get to a working answer, but it didn't work fully for me, due to some security cake plugins that I have installed.
Here's what worked for me:
$(function(){
$('a:contains("Delete")').removeAttr('onclick');
$('a:contains("Delete")').click(function(e){
e.preventDefault();
var form = $(this).prev();
var url = $(form).attr("action");
$.ajax({
type: 'POST',
cache: false,
url: url,
data: $(form).serialize(),
success: function(msg) {
// do any extra calls you need to refresh the page
}
});
return false;
});
});
Just an idea, haven't tested it:
<?php echo $this->Form->postLink('Delete', array('action'=>'delete', $prospect['Prospect']['id']), array('class'=>'postLink', 'onclick' => false, 'escape'=>false), __('Sure you want to delete # %s?', $prospect['Prospect']['id'])); ?>
Couple of issues with the current solutions...
First and foremost, the postLink method requires Javascript to be enabled. From Cake's doco:
"Creates an HTML link, but access the url using method POST. Requires javascript to be enabled in browser."
If javascript is disabled, you just get the exact same output - a hidden form, and a link that tries to submit that form with Javascript (but fails, since JS is turned off).
Second, although it will work, it seems weird to use the postLink method, and then use Javacript to undo precisely all the magic that the postLink method creates.
If you want a non-javascript friendly solution, all you have to do is create a regular form that points to the delete method, and put a link below it like this:
<?php echo $this->Form->create('DefaultAvailability', array('url' array('action' => 'delete', $myRecord['ModelName']['id'])));?>
<?php echo $this->Form->end('Delete (no JS)');?>
<a href='#'>Delete (With JS, use AJAX)</a>
Then, for cases when there's no javascript, hide the link below, and the form will work as normal.
For cases when there is javascript, hide the form, and use javascript to make your delete link trigger a submit on your delete form, and handle that submit with ajax.
I've translated the previous jQuery version to Mootools
//We start with foreach, to select all ajax buttons on the page
$$('.ajaxbutton').each(function(item,index){
//remove onClick
item.removeProperty('onclick');
//attach click event
item.addEvent('click', function(e){
//stop click (in my case the form is inside another link)
e.stop();
var form = item.getPrevious();
url = form.get('action');
new Request({
url: url,//url
method: 'post',//method
onSuccess: function(responseText){
//This is not required, we are dimming the button on success
item.getParents()[0].tween('opacity',0.5)
}
}).send();
return false;
});
})
I have an Ext.Panel with a listener set to 'afterrender'. The callback function is a small ajax code which checks an url, grabs it's contents and add it to the panel. Problem is, the content does not get insterted. If I use the same insert code right above the ajax call, it works. Here's my callback function:
Not working:
function afterrenderCallback () {
// This does not work
var logPanel = Ext.getCmp('aP_ServerLogs');
Ext.Ajax.request({
url: AP_ROOT_URL + '/index.php?r=server/logs',
success: function (r) {
logPanel.add({
html: 'dummy html i don\'t care about the response'
});
}
});
}
Working:
function afterrenderCallback () {
// This does work
var logPanel = Ext.getCmp('aP_ServerLogs');
logPanel.add({
html: 'dummy html i don\'t care about the response'
});
}
You might need to call doLayout() on the panel. However check out Ext.Updater:
http://dev.sencha.com/deploy/dev/docs/?class=Ext.Updater
Panels have this automatically such as:
var panel = new Ext.Panel({
});
panel.body.load(...);
panel.body.update(...);
I'd suspect the callback isn't getting called. You could add a failure case with a simple alert call to check it's not going down that path.
However probably better, similar to what #Lloyd said, you should look at the autoLoad config property.
The autoLoad config is what you want, as mentioned. I wanted to add that doing a logPanel.add({...}) just to insert markup is not appropriate, even though it "works". There is no reason to nest a panel within a panel for this. If you are loading HTML content like this you'd preferably do logPanel.body.update('content');.
As #bmoeskau says, the autoLoad config is what we need. It took me quite a while to find the correct syntax though. So here is an example on how to define such a panel with ajax content:
Ext.define('MyApp.view.aP_ServerLogs', {
extend : 'Ext.panel.Panel',
id: 'aP_ServerLogs',
loader: {
url: AP_ROOT_URL + '/index.php?r=server/logs',
autoLoad: true
}
});