What does it take to build a system like Facebook comments where new comments are loaded into the display automatically? Is anyone working on an AJAX capability to submit comments without reloading the page?

CommentFileSizeAuthor
#20 reply.module.txt54.19 KBadamtong

Comments

Anonymous’s picture

Status: Active » Postponed

It's not hard at all but currently it's not in to do list.

rogical’s picture

AJAX Comments, Inline Ajax Comments this two modules can work for you.

For this module, we can plan to integrate with nodejs in the future.

eidoscom’s picture

Hi here,

I'm trying to configure the reply form as an AJAX form in order to let the user post a Reply and reload the page with AJAX. Make the form controlled with AJAX is easy, you only need to add this code to reply_add_form() function on reply.module file:

$form['submit']['#ajax'] = array(
    'callback' => 'reply_submit_js',
    'wrapper' => '#replies-wrapper-' . $entity_id,
    'method' => 'replace',
    'effect' => 'fade',
  );

Where 'callback' tells the Form system what callback should be called after the AJAX call happens and the form is rebuilt, and the 'wrapper' is the HTML ID of a page section that should be replaced (or altered in some other way).

The modules commented on #2 are not working with Reply because are focuset on the drupal core comment system. So we need an alternative...

All that I have done let the form submitted by AJAX, but I need to have the new "replies set" to output via the callback function. I'm trying to use the 'reply_build_content' function but the system throws me an error :

ResponseText: EntityMalformedException: Missing bundle property on entity of type reply. en entity_extract_ids() (línea 7539 de (mysite)/includes/common.inc).

Anny suggestion??

james.williams’s picture

Can you post here the contents of your reply_submit_js() function?

eidoscom’s picture

At the moment, all that i Have is this:

function reply_submit_js($form, &$form_state) {
  if ($errors = form_get_errors($form)) {
    // As we are submitting via ajax, we must prepend validation to the form
    $commands[] = ajax_command_prepend('#' . $form['#id'], theme('status_messages'));
    return array('#type' => 'ajax', '#commands' => $commands);
  }
  
  //Get the entity id from the form
  $reply_id = $form['entity_id']['#value'];
  
  //Append the new reply with AJAX
  $reply_output = reply_build_content($reply_id);
  $commands[] = ajax_command_append('#' .'replies-wrapper-' . $reply_id, 'TEXTE: ' . $reply_output);

  return array('#type' => 'ajax', '#commands' => $commands);
}
james.williams’s picture

Check the reply_build_content() parameters:

/**
 * Builds content property for displaying an entity.
 *
 * @param $reply object
 *    The reply entity object.
 * @param $view_mode string
 *    The mode of view to use to generate a view.
 * @param $langcode string
 *    The language code of this view.
 */
function reply_build_content($reply, $view_mode = 'full', $langcode = NULL) {

You need to pass the full reply entity, not just its ID.

eidoscom’s picture

<?php
/*
 * dpm($replies);
*/
//Get the number of Replies
$n = count($replies);

$entity_id = $reply_form['entity_id']['#value'];
//dpm($reply_form);
?>
<div class="replies-wrapper">
  <?php print('Hay ' . $n . ' comentarios'); ?>
  <?php if (!empty($header)) : ?><div class="replies-header"><h3><?php print $header ?></h3></div><?php endif; ?>
  <div class="replies" id="replies-wrapper-<?php print $entity_id ?>"><?php print render($replies) ?></div>
  <?php if ($links): ?><div class="replies-links"><?php print render($links) ?></div><?php endif ?>
  <?php if ($reply_form): ?><div class="replies-form"><?php print render($reply_form) ?></div><?php endif; ?>
</div>

This is my personalized replies.tpl.php in order to understand the "replies-wrapper-id" selector.

Thanks!

eidoscom’s picture

Yes, I know that is not enough with the entity_id extracted from form, moreover, this entity_id is refered to the entity that have the replies attached to ... Can I get the object from this id?? how?

james.williams’s picture

You can load a reply with reply_load($reply_id). However I'm not sure the reply itself will actually be available to you, in $form_state or anywhere else.
I see comment module has this line: $form_state['values']['cid'] = $comment->cid; in comment_form_submit(). You may wish to add something similar in our reply_add_form_submit() so that you can access the created reply.

eidoscom’s picture

As I understand, I need to recreate the array of replies attached to the entity that has the "entity_id" in order to render again and replace the old data with the new data.

I think that is the same that module do when an entity that have "Reply enabled" is rendered... I think that the module must use the 'entity_id' like I need here, but I can't find where in the code can get this actions ....

Still searching for the solution.

james.williams’s picture

Ah okay I misunderstood what you are trying to do.

The reply module would normally display replies on an entity through a field formatter, reply_field_formatter_view(). So what you actually want to do is just display your reply field on the parent entity (assuming your field instance settings work in this way). Try calling field_view_field(). For example:

$entity_id = $reply_form['entity_id']['#value'];
$entity_type = $reply_form['entity_type']['#value'];
$entity = entity_load($entity_type, array($entity_id));
$reply_output = field_view_field($entity_type, $entity, 'field_my_reply_field_on_the_parent_entity');
eidoscom’s picture

Hi James,

First of all thanks for your quick support ;)

I think that I'm not explaining well what I want to do :S

I'm trying to manage the replies with AJAX. I configured As I posted above (#3), the form is submitting via AJAX with no other problems. The database gets the right values. I need to refresh the reply list (replies) with the new one in order to show the recent changes of the replies

I can do by two ways:

  1. Load all reply set related to my Entity and replace with the new set (with the just submitted reply)
  2. Only add the just submitted reply

I want to have 1 or 2 in a string format in order to output via AJAX.

Sorry about my English I do my best ...

eidoscom’s picture

I tried your last code and throws me another error:

ResponseText: EntityMalformedException: Missing bundle property on entity of type message. en entity_extract_ids() (línea 7539 de (mysite)/beta7/includes/common.inc).

The entity of type Message is the entity that has the "field_comentarios" reply field.

eidoscom’s picture

Okay!!

It seems that I did it!!

This is the code for the callback function.

function reply_submit_js($form, &$form_state) {
  if ($errors = form_get_errors($form)) {
    // As we are submitting via ajax, we must prepend validation to the form
    $commands[] = ajax_command_prepend('#' . $form['#id'], theme('status_messages'));
    return array('#type' => 'ajax', '#commands' => $commands);
  }
  
  //I don't know what exactly is this ...
  $reply = (object) $form_state['values'];
  
  //construct the new reply view
  $reply_output = reply_view($reply);
  $reply_output = drupal_render($reply_output);

  $commands[] = ajax_command_before('#' . $form['#id'], $reply_output);

  return array('#type' => 'ajax', '#commands' => $commands);
}

Now it's working !!

eidoscom’s picture

Hi again

This is working well, but the Reply form still has the old values... And moreover, the new form is not processing by AJAX.

I use the reply_add_form() to build the form where I added this:

//Add the Ajax class to submit the form via AJAX
  $form['submit']['#ajax'] = array(
    'callback' => 'reply_submit_js',
    'wrapper' => 'replies-wrapper-' . $entity_id,
    'method' => 'replace',
    'effect' => 'fade',
  );

I think that if I use the reply_add_form() function to build the new form, the AJAX class must be attached to the new form, but this is not working...

Here is the code that I use as ajax callback:

function reply_submit_js($form, &$form_state) {
  if ($errors = form_get_errors($form)) {
    // As we are submitting via ajax, we must prepend validation to the form
    $commands[] = ajax_command_prepend('#' . $form['#id'], theme('status_messages'));
    return array('#type' => 'ajax', '#commands' => $commands);
  }

  $reply = (object) $form_state['values'];
  $bundle = reply_bundle_load($reply->bundle);

  // Get the entity info from the form
  $entity_id = $form['entity_id']['#value'];
  $entity_type = $form['entity_type']['#value'];
  $entity_instance = $reply->instance_id;
  $entity_bundle = $form['bundle']['#value'];
 
  
  //construct the new reply view
  $reply_view = reply_view($reply);
  $reply_output = drupal_render($reply_view);
  $commands[] = ajax_command_before('#' . $form['#id'], $reply_output);

  //Rebuild and render the form and replaces the old one with the new one (cleaned)
  $form_build = reply_add_form($form, $form_state, $entity_id, $entity_instance);
  $form_output = drupal_render($form_build);
  $commands[] = ajax_command_replace('#' . $form['#id'], $form_output);

  return array('#type' => 'ajax', '#commands' => $commands);
}

Some idea about this??

achilles085’s picture

@eidoscom did you manage to get the solution?

eidoscom’s picture

Nope....

With the code above you can submit the replies via AJAX but only the first one... If you try to submit a second one is not AJAX processed and if you add some extra fields like images the files are correctly submited but not showing well in the AJAX created new reply .... I think this last is because must define some waiting time until the file is uploaded

It's a little wired and I'm not working on it at the moment ... If you get this code and the problems that I posted here you can try to continue ;)

churel’s picture

@eidoscom and @achilles085 :

I have the same problem. Your code is ok but you need to rebuild the form before send it by ajax (without that no form_alter etc...). What you need to do is :

function globule_video_ajax_comment_submit(&$form, &$form_state) {
    $reply = (object) $form_state['values'];
    entity_form_submit_build_entity('reply', $reply, $form, $form_state);
    reply_save($reply);
    $bundle = reply_bundle_load($reply->bundle);
	
  // Get the entity info from the form
  	$entity_id = $form['entity_id']['#value'];
 	 $entity_type = $form['entity_type']['#value'];
 	 $entity_instance = $reply->instance_id;
  	$entity_bundle = $form['bundle']['#value'];
	
	//construct the new reply view
  	$reply_view = reply_view($reply);
  	$reply_output = drupal_render($reply_view);
 	 $commands[] = ajax_command_before('#' . $form['#id'], $reply_output);
	
	//Rebuild and render the form and replaces the old one with the new one (cleaned)
	$new_form_state = array();
	
	$new_form_state['build_info']['args'] = $form_state['build_info']['args'];
        // Build a new un-cached reply form
	$new_form_state['input'] = array();
       // $form_build = drupal_build_form('reply_add_form' . $entity_id .'_'. $entity_instance, $new_form_state);
	 $form_build = reply_add_form($form,$new_form_state , $entity_id, $entity_instance);
	$form_output = drupal_render($form_build);
	 $message_form_state['input'] = array();
	$commands[] = ajax_command_replace('#' . $form['#id'], $form_output);		
      return array('#type' => 'ajax', '#commands' => $commands);
	

}

and it work.

adamtong’s picture

Hi, can you tell me where to add the code in the files? And what is the most updated code should I add?

Thank you in advance.

adamtong’s picture

StatusFileSize
new54.19 KB

I have tried to add the code. But there is a bug that the reply submitted twice after reload the page.

I add the following code at around line 986:

//Add the Ajax class to submit the form via AJAX
  $form['submit']['#ajax'] = array(
    'callback' => 'reply_submit_js',
    'wrapper' => 'replies-wrapper-' . $entity_id,
    'method' => 'replace',
    'effect' => 'fade',
  );
 

And this code after

return $form;
}

/**
 * Reply submit js function
 */
function reply_submit_js(&$form, &$form_state) {
    $reply = (object) $form_state['values'];
    entity_form_submit_build_entity('reply', $reply, $form, $form_state);
    reply_save($reply);
    $bundle = reply_bundle_load($reply->bundle);
    
  // Get the entity info from the form
      $entity_id = $form['entity_id']['#value'];
      $entity_type = $form['entity_type']['#value'];
      $entity_instance = $reply->instance_id;
      $entity_bundle = $form['bundle']['#value'];
    
    //construct the new reply view
      $reply_view = reply_view($reply);
      $reply_output = drupal_render($reply_view);
      $commands[] = ajax_command_before('#' . $form['#id'], $reply_output);
    
    //Rebuild and render the form and replaces the old one with the new one (cleaned)
    $new_form_state = array();
    
    $new_form_state['build_info']['args'] = $form_state['build_info']['args'];
        // Build a new un-cached reply form
    $new_form_state['input'] = array();
       // $form_build = drupal_build_form('reply_add_form' . $entity_id .'_'. $entity_instance, $new_form_state);
     $form_build = reply_add_form($form,$new_form_state , $entity_id, $entity_instance);
    $form_output = drupal_render($form_build);
     $message_form_state['input'] = array();
    $commands[] = ajax_command_replace('#' . $form['#id'], $form_output);        
      return array('#type' => 'ajax', '#commands' => $commands);
}

Attached is the reply.module I changed

Please help.

Thank you in advance.

niallmurphy-ie’s picture

Issue summary: View changes

Has anyone ever gotten Ajax to work?

Edit: Nevermind, I took the code here and somehow adapted it to the 7.x-2.x-dev code and it's working fine with errors. I'll post it tomorrow.