0

I am trying to create a custom field type widget with a ajax submit handler to save the value of the field to the database without saving the whole node.

Here is my code hook_field_field_info().

function mymodule_field_info() {
  return array(
   'time_logger_time' => array(
   'label' => t('Time loger'),
   'description' => t('Custom Poutine Field'),
   'default_widget' => 'time_logger_time_widget',
   'default_formatter' => 'time_logger_default_formatter',
   ),
  );
 }

Than this is my hook_field_widget_info()

function mymodule_field_widget_info() {
   return array(
   'time_logger_time_widget' => array(
   'label' => t('Default'),
   'field types' => array('time_logger_time'),
  ),
 );
}

And finally my hook_field_widget_form() looks like

function mymodule_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
    $value = isset($items[$delta]['id']) ? $items[$delta]['id'] : '';
     $element['id'] = array(
       '#type' => 'textfield', 
       '#size' => 6,
       '#default_value' => $value
      );

     $element[submit] = array(
      '#type' => 'button',
      '#value'=>'Save',
      '#name' =>  'submit-'. $delta,
      '#ajax' => array(
        'callback' => 'mymodule_ajax_handler',
        'effect' => 'fade',
       ),
   );
   return $element;
 }

Idea is when I click the save button in my widget form it will call my ajax callback load the node, set the value of my field and save the node as follows-

function mymodule_ajax_handler( $form, &$form_state){
     $node = node_load(22);
     dsm( $node);
     $node_wrapper = entity_metadata_wrapper('node', $node);
     $node_wrapper->field_log->set(1);
     $node->save();
 }

But when I click button I am getting some error saying "Notice: Undefined index: field_log in EntityStructureWrapper->getPropertyInfo() (line 334 of /var/www/html/mysite/sites/all/modules/contrib/entity/includes/entity.wrapper.inc)."

If I change my field in the ajax callback to some other field in my content type its saving fine. Like below-

function mymodule_ajax_handler( $form, &$form_state){
 $node = node_load(22);
 $node_wrapper = entity_metadata_wrapper('node', $node);
 $node_wrapper->some_other_field_from_my_content_type->set(1); //This works fine 
 $node->save();
}

Is there anything wrong in my widget form.

Here is my field scheme if someone want to refer-

function mymodule_field_schema($field) {
$schema = array();
$schema['columns']['id'] = array(
    'type' => 'varchar',
    'length' => 50,
    'not null' => FALSE
);
  return $schema;
}
5
  • How do you know the end user (you) named the field field_log? That name is the system name you give on the Manage Fields page. It can differ per user, so you should not be making assumptions on that name unless you manually create and lock the fields and field instances in eg hook_enable(). May 22, 2016 at 23:24
  • Hi Thanks for your replay. I did not understand your point here. Are you saying I should not use a field with machine name "field_log"? May 23, 2016 at 6:55
  • I do not know about the intention of you module, but if it is only for your site you are fine. If others touch the site you cannot be sure they will name the field the same. May 23, 2016 at 7:33
  • I can change the field that is not a issue for me. My module is something on logging time on the particular node(work item content type). I want to design it as a field widget. So that I can add this field anywhere else as required. This widget will show a progress bar in the UI along with a button to log time. When the user clicks on the button it will open a small popup with field to add time he spent on the particular item. In the popup there will be another button to save the time once clicked it will update the field. thats all May 23, 2016 at 13:47
  • Though it was not an answer to your question, the point was that if you add this field to another node and name it field_log2 it will never work because the name field_log is hardcoded in your AJAX callback. You should not hardcode field names in your modules if a user can freely choose those names. May 23, 2016 at 13:55

2 Answers 2

0

There might be a few issues, but it hard to tell.

First make sure the field is actually on the node. (Source https://www.drupal.org/documentation/entity-metadata-wrappers):

function _wrapper_debug($w) {
  $values = array();
  foreach ($w->getPropertyInfo() as $key => $val) {
    $values[$key] = $w->$key->value();
  }
  return $values;
}

dpm(_wrapper_debug($some_wrapped_object));

If it is there, perhaps you made the field a multi value field (it can hold more then 1 value), in this case you need to assign it like this:

 $node_wrapper->field_log[]->set(1); // Note the extra []

If this does not solve the problem, have a look at the above metadata wrapper page. It comes with a lot of examples en explanations.

7
  • What is $some_wrapped_object ? Is that a node object? like - $nid =22; $node =node_load($nid); May 23, 2016 at 14:26
  • That is an entity metadata wrapped node; In your case $node_wrapper = entity_metadata_wrapper('node', $node); it would be $node_wrapper. May 23, 2016 at 14:27
  • Yes you are right I am not seeing my field. Whats wrong? But it is added in my content type. I can also see the field in the UI. May 23, 2016 at 14:35
  • Are you sure you have the good node? Node 22 is of a content type that has that field attached? May 23, 2016 at 14:39
  • yes field is there in node 22. I am calling dsm from hook_field_is_empty is that fine? May 23, 2016 at 14:40
0

Finally I am able to do this with "property_type" in my hook_field_info(). Posting it here hope someone will get some help someday.

Following is my updated hook_field_info -

function mymodule_field_info() {
  return array(
  'time_logger' => array(
  'label' => t('Time loger'),
  'description' => t('Field that keep track time loged on work items.'),
  'default_widget' => 'time_logger_time_default_wedget',
  'default_formatter' => 'time_logger_default_formatter',
  'property_type' => 'my_property_type',
  'property_callbacks' => array('my_property_info_callback'),
  ),
 );
}

Than my property type callback _

function time_logger_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {
   $property = &$info[$entity_type]['bundles'][$instance['bundle']] ['properties'][$field['field_name']];
   $property['getter callback'] = 'entity_metadata_field_verbatim_get';
   $property['setter callback'] = 'entity_metadata_field_verbatim_set';
   unset($property['query callback']);
  $property['property info']['lid'] = array(
    'type' => 'text',
    'label' => t('Log id'),
    'setter callback' => 'entity_property_verbatim_set',
  );
  $property['property info']['total_loged_time'] = array(
    'type' => 'text',
    'label' => t('Total logged time.'),
    'setter callback' => 'entity_property_verbatim_set',
   );
}

Than finally my ajax callback is here_

function time_logger_log_time( $form, &$form_state){
   global $user;
   $parents = $form_state['triggering_element']['#array_parents'];
   $values = $form_state['values'];
   $field_name = $parents[0];
   $language_code = $parents[1];
   $delta = $parents[2];
   $nid = $form_state['values']['nid'];
    $node_wrapper->$parents[0]->set(array('field1'=>'something','field2'=>'something'));  
    $node_wrapper->save();
 }

Thanks to @Neograph734 for pointing me to the right direction.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.