Drupal 7 ajax_command_* creates unwanted div - ajax

I'm populating a select box using an AJAX callback in Drupal 7. I've tried both ajax_command_append() and ajax_command_html() to set the new <option...> statements, but both these wrap the HTML that I create inside a <div>. This causes the <select> to not display any of the options.
Is there a way to tell Drupal "Hey stupid, this is exactly the HTML I want, don't mess with it"?
I can code some jQuery to remove the div I guess, but it would be a lot better if I can prevent it from being added in the first place.

Yes you can!
Declare your own custom js callback. In below example, I used a span instead of the divs. But you can obviously remove the wrapper alltogether.
PHP:
function my_ajax_callback() {
$data = 'saved!';
// instead of using ajax_command_html, we provide our own
// js custom callback function
$output = array(
'#type' => 'ajax',
'#commands' => array(
array('command' => 'myjscallback', 'data' => $data),
),
);
return $output;
}
JS:
$(function() {
Drupal.ajax.prototype.commands.myjscallback = function (ajax, response, status) {
$('#save-btn-message').html('<span>' + response.data + '</span>');
};
});

The answer is yes.
Just use this instead:
$commands[] = ajax_command_invoke('#mywrapper', 'html', array($output));

So it seems the answer is "no" (or at least not without hacking core, and I'll have no dead kittens on my conscience).
misc/ajax.js contains the following:
var new_content_wrapped = $('<div></div>').html(response.data);
The comments therein go on to explain why they require the first HTML element to be a top-level one. If it is, the <div> wrapper is not used. In my case, I'm replacing <option> elements, so I get the <div>.
Now I could just replace the entire <select>, but that causes other issues in my case due to scripts that style things at page load. Rather than find those and re-fire them, it looks like it'll be easier to just ajax_command_invoke a script to run after my options are loaded to remove the div wrapper.
EDIT: As a workaround, I found I can do ajax_command_invoke($selector, 'html', array('<option...>')); and it bypasses the div addition code. Kinda sneaky, but it works...

you can use seen on this link http://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7#ajax
for more reference and example download this module http://drupal.org/project/examples
it has all the examples of custom code and "ajax_example" as well

It works for me!
$selector = '#my-select';
$method = 'append';
$opts = array('new option');
$commands[] = ajax_command_invoke($selector, $method, $opts);
return array('#type' => 'ajax', '#commands' => $commands);

Related

Drupal ajax form, partial render

Good day.
I created custom form in my module and defined submit button like this:
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
'#ajax' => array(
'callback' => 'fmg_addbanner_ajax_callback',
'method' => 'replace',
'wrapper' => 'banner_add_wrapper'
)
);
Then outputted my form like this:
$form = drupal_get_form('fmg_banner_add_form', $region_id);
print render($form);
But ajax requests don't work. I think because of there are no needed drupal js files. How can I solve this problem? Thanks.
The normal case will be to have #ajax attached to a common input, like checkbox, text box etc.
The behavior is that when user change the input value, it'll fire your callback through ajax and send entire form over, and then you can process this form behind the scene and adjust certain things before sending the form back and change the element to the wrapper you defined.
One of the question that I had for partial form rendering is when I need to do some ajax call or inject partial form element to certain area of the page while keeping the integrity of the form rendering. (I don't know exactly what form build did, i guess i don't want to know)
Since form rendering uses the renderable array, if you just want to extract certain element, you could just do
$form = drupal_get_form('application_form');
$body = render($form['body']);
The following is a real example that i took a form and split into header, footer and the rest of form elements.
// get a form for updating application info.
$form = drupal_get_form('pgh_awards_review_application_form', $app);
$elements = array();
$form_render = render($form);
$elements = array(
'qualify' => render($form['qualify']),
'threshold_met' => render($form['threshold_met']),
'submit' => render($form['submit']),
);
if (preg_match('/<form.+div>/', $form_render, $matches)) {
$elements['header'] = $matches[0];
}
if (preg_match('/<input type="hidden".+form>/s', $form_render, $matches)) {
$elements['footer'] = $matches[0];
}
$vars['form'] = $elements;
It's definitely not pretty approach, it just serves the needs at the moment.

Drupal Form API : display the same form again with AJAX, but with different values, on submit

this is my first post on Stackoverflow, after reading perhaps hundreds of thoughtful questions and no less useful answers.
My point is, today, I never found an (even dirty) way to do what I intend to do, and never managed to find an answer, although it seems quite improbable that no one ever had the same request and/or problem.
Which is, by the way...
Calling the same form again with AJAX, but with different values than those previously entered by the user
The idea
I've got a Drupal Form (a normal form built with Drupal Form API) with textfields and an AJAX-ified submit button. This form is displayed through an AJAX call and is itself AJAX-ified, so.
When I click on 'Submit', I want to do some stuff like looking in the database, updating some values, etc, based on what the user entered in the form. And then, I want to ajax-display the same form again, but with different values than those entered by the user in the first instance of the form.
Everything goes fine with doing whatever I want during the processing, but whatever I do, no matter what, I face the same problem again and again :
The problem
When the new instance of the form is displayed, it is displayed with the previous values (those entered by the user). I never was able to display other values than those previously here in the form when "Submit" was clicked in the previous instance of the form.
Simple example
What I'm actually trying to do is quite complex, with several ajax_commands and a bit of processing, but here is a simpler example that faces exactly the same problem :
function ajax_first_callback_to_my_form($type = 'ajax') {
// here the first instance of the form is ajax-called. No problem with that.
$mail = 'example#mail.com';
$first_message = 'Please enter an email address...';
$commands = array();
$commands[] = ajax_command_replace('#my_ajax_wrapper', display_my_form($mail, $first_message));
$page = array('#type' => 'ajax', '#commands' => $commands);
return($page);
}
function display_my_form($mail, $message) {
// the function used to display the form.
// it can be called by the first ajax callback (the previous function in this example)
// or by the ajax callback triggered by clicking 'submit' on the form itself.
$form = drupal_get_form('my_form', $mail, $message);
$display = '<div id="my_ajax_wrapper">';
$display .= render($form);
$display .= '</div>';
return $display;
}
function my_form($form, &$form_state, $mail, $message) {
// the form constructor
$form = array (
'email' => array (
'#type' => 'textfield',
'#default_value' => $mail,
'#suffix' => '<div id="my_message">'.$message.'</div>',
),
'submit' => array (
'#type' => 'submit',
'#ajax' => array (
'callback' => 'my_ajax_callback', ),
),
);
}
function my_ajax_callback($form, &$form_state) {
// triggered by clicking 'submit' in the form
$mail = $form_state['values']['email'];
if ($mail == 'correct_mail#gmail.com') {
$new_mail = 'different_mail#gmail.com';
$new_message = 'You entered a correct email and here is your new one';
} else {
$new_mail = $mail;
$new_message = 'You entered an incorrect mail, please correct it';
}
$commands = array();
$commands[] = ajax_command_replace('#my_ajax_wrapper', display_my_form($new_mail, $new_message));
$page = array('#type' => 'ajax', '#commands' => $commands);
return($page);
}
function my_form_submit($form, &form_state) {
// my_form submit handler
$form_state['rebuild'] = true; // appears necessary, otherwise won't work at all
}
Okay, it was quite a long piece of code but it seemed useful to fully understand my question.
Processing stuff happens correctly...
All the stuff I want to do in my_form_submit or in my_ajax_callback is properly done. If I check the variables in display_my_form() they are correctly updated.
... but the new instance of the form doesn't take it into account
But whatever I can try, the next time the form is displayed with AJAX, the email field will be 'example#mail.com' as its default value (or any different mail entered by the user), and the message div will be filled with 'Please enter an email address...'.
I tried MANY ways of doing this differently, putting the after-submit processing in the ajax callback, in the my_form_submit function, using $_SESSION variables instead of passing them through the different functions, using the database... None of this works.
What to do ?
Quite annoying. This is not the first time I encountered this problem. Last time I could find a workaround, simply by giving up this idea of re-displaying the same form through AJAX, but now I really would appreciate being able to do this.
Could the problem be related to $form_state['rebuild'] ?
By the way, I'm curious about it : have you encountered this problem before ? Is it something simple which I'm missing out ? If it's a bug, could this bug be Drupal-related, or AJAX-related... ?
Any help or ideas will be truly appreciated. Thank you for your time.
I came up with a solution to this one :
If you are to display the same form again with AJAX, for instance with this function (called by your AJAX callback), no matter what you'll do, it will display the same values again and again :
// It doesn't work :
function display_my_form($mail, $message) {
$form = drupal_get_form('my_form', $mail, $message);
$display = '<div id="my_ajax_wrapper">';
$display .= render($form);
$display .= '</div>';
return $display;
}
If you want to change the fields values when refreshing the form, you have to update the form manually, after having called it again, by adding this kind of line :
// It works :
function display_my_form($mail, $message) {
$form = drupal_get_form('my_form', $mail, $message); // $variables are simply ignored if the form is already displayed. Rebuilding it won't change a thing.
$form['email']['#default_value'] = $mail; // update a part of the form
$form['email']['#suffix'] = $message; // update another part of the form
$display = '<div id="my_ajax_wrapper">';
$display .= render($form);
$display .= '</div>';
return $display; // sends $display to our AJAX callback, and everything's fine now
}
Contrary to easy belief one (such as... me) can first have about it, the form doesn't take into account the variables it's being sent with drupal_get_form, when already constructed and recalled by AJAX.
It's just not enough to update the variables, and do drupal_get_form again. You have to do drupal_get_form, and afterwards manually update the parts of the form you want updated.
Hope this will help someone.
Well I am quite confident about your issue if this is the case:
$commands[] = ajax_command_replace('#my_ajax_wrapper', display_my_form($new_mail, $new_message));
The problem is not anything else its just the id you are passing.You need a class and not the id "#my_ajax_wrapper", because id might get changed but class won't in this case.
Try with this you should get the result as you want.
Note: to make it work, one needs to add this in form_submit handler:
function my_form_submit($form, &$form_state)
{
$form_state['rebuild'] = true;
}

WordPress Excerpt - Javascript - PHP - Ajax?

I've created this script inside my home.php file for my WordPress theme to calculate the value of a div width in relation with a number (1.408). This operation give me the result (inside $chars variable) to establish number of characters to use in the excerpt for Responsive Design. If the div is larger or thinner, I'll have a different number of characters for my WordPress Excerpt.
This is the code I've published on HOME.PHP. Javascript followed by PHP code for excerpt.
I know javascript variable inside PHP is impossible without Ajax (reading on other forums), but I cannot understand what exactly to do. I am not so good with code. Be clear please and if possible with some examples!
<script type='text/javascript'>
jQuery(document).ready(function() {
var $myDiv = jQuery('#last_post_img_text');
var $results = jQuery('#results');
var $chars = jQuery( $myDiv.outerWidth()/1.408 );
</script>
<?php new_excerpt( $chars ); ?>
I would suggest an approach:
Load a page, check conteiner element width and height, then use $.ajax to load elements content, and send some kind of a variable to decide how many characters to use.
If You would like to do it in WordPress way, read about:
add_action('wp_ajax_$handlename', 'function_to_run');
add_action('wp_ajax_nopriv_$handlename', 'function_to_run');
that will reposnd to Yours ajax request.
wp_enqueue_script( 'theme_js', get_bloginfo('template_url') . '/js/jquery-theme.js', array('jquery'), THEME_VERSION, false );
$protocol = isset( $_SERVER["HTTPS"] ) ? 'https://' : 'http://';
$params = array( 'ajaxurl' => admin_url( 'admin-ajax.php', $protocol ) );
wp_localize_script( 'theme_js', 'theme_js', $params );
this might come handy, if You dont know how to send wp-ajax.php localisation to jQuery $.ajax request.
Reloading the comments with Ajax seems like a bad decision. Why would you want to keep reloading content that doesn't really change. I think your best bet is to use a jQuery plugin.
One that seems to do what you want is http://www.bramstein.com/projects/text-overflow/.
Alternatively you can check out the CSS3 property 'text-overflow' (http://www.w3schools.com/cssref/css3_pr_text-overflow.asp).

How can I return actual JSON using Drupal?

I'd like to implement a simple AJAX function locally that allows me to autocomplete node titles of already existing nodes as the user types. To that end, I need the ability to have an API that I can search on node titles. The problem is that when I output raw JSON, it comes surrounded by tags. So, no matter what I do, I keep getting...
<html>
<head>
</head>
<body>
<pre style="word-wrap: break-word; white-space: pre-wrap;"> {json here}</pre>
</body>
</html>
I've tried implementing a custom page template that only outputs content already, that produced the same results. Here is how I am currently doing this, in my module file...
<?php
/**
* Implementation of hook_menu()
*/
function content_relation_menu() {
$items = array();
$items['api'] = array(
'title' => 'Search',
'page callback' => 'content_relation_get',
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
function content_relation_get($term = '') {
drupal_add_http_header('Content-Type', 'application/javascript; utf-8');
$var = json_encode(
db_query("SELECT nid,title FROM {node} WHERE title LIKE :title LIMIT 5", array(":title" => $term.'%'))->fetchAll()
);
echo $var;
exit(0);
}
How can I return JUST raw JSON?
The 'Drupal' way is using drupal_json_output() and drupal_exit().
$data = db_query("SELECT nid,title FROM {node} WHERE title LIKE :title LIMIT 5", array(":title" => $term.'%'))->fetchAll();
drupal_json_output($data);
drupal_exit();
UPDATE
I've just put your code, as is, into a module and all I get when requesting http://site.com/api is the expected JSON, there are no tags. The problem won't be anything to do with Drupal, more likely to do with server/browser configuration.
This link may help:
What do browsers want for the Content-Type header on json ajax responses?
This actually DID output raw JSON - Chrome was adding the html wrapping. Viewing the output in command line cURL showed that this did output raw JSON.
Take out the exit(0); and it should work. If your page callback doesn't return anything then the normal theme handlers don't get called so you get raw output.
That said, due to the rather poor performance of Drupal, for decent response times you're better off making a small standalone script that talks to the drupal DB, so you don't pay the rather heavy startup costs of a drupal request when you don't need of that functionality.

$ajax->submit Does Not Go To Controller

I am using cakephp and pippoacl plugin and I simply cannot add a new role. What I modify in the plugin is to make the submit using ajax, something like this in my view (add.ctp):
<?php echo $ajax->submit(
'submit',
array(
'url' => array('controller' => 'roles', 'action' => 'add'),
'before' => 'beforeSubmitAdd();',
'complete' => 'completeSubmitAdd(request);'
)
);
?>
When the add.ctp gets loaded for the first time, I can print_r something from the controller. But the ajax submit above only executes the javascript on 'before' and 'complete'. I check on the firebug, the response is blank.
On my controller:
function add() {
print_r("start");
if (!empty($this->data)) {
print_r("add new role");
// save new role
}
}
I use ajax submit for user and I don't have any problem adding new user. Is there any idea where I should check? I have been comparing the user and role code for a week and I have asked a friend to look at my code, too, but we still cannot find what causes this.
Thanks in advance! :D
I am not so familiar with the Ajax helper, but I haven't using it from so long that I can't remember what is it doing :).
Back to the problem.
Did you check if the requested URL in the Ajax address is correct? This should work straightforward, but it's possible that the url to be invalid.
Are you using Security component (even just adding it on the var $components variable)?. This could lead to blank screen especially if you modifying the fields in the form somehow. Try to remove it and see if it's working without.
Finally I would say how I would do it with jQuery.
Following code should do the job:
$(document).ready(function(){
$('form').live('submit', function(){ //handles also dynamically loaded forms
var form = $(this).addClass('loading'); //indicate somehow that the form has been submitted
$('#content').load($(this).attr('action'), $(this).serialize(), function(){
form.removeClass('loading');
});
})
});
This will handle all submits in the forms of the system, but you can modify of course.

Resources