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;
}
  • 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(). – Neograph734 May 22 '16 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"? – Nabajit Roy May 23 '16 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. – Neograph734 May 23 '16 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 – Nabajit Roy May 23 '16 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. – Neograph734 May 23 '16 at 13:55
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.

  • What is $some_wrapped_object ? Is that a node object? like - $nid =22; $node =node_load($nid); – Nabajit Roy May 23 '16 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. – Neograph734 May 23 '16 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. – Nabajit Roy May 23 '16 at 14:35
  • Are you sure you have the good node? Node 22 is of a content type that has that field attached? – Neograph734 May 23 '16 at 14:39
  • yes field is there in node 22. I am calling dsm from hook_field_is_empty is that fine? – Nabajit Roy May 23 '16 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, privacy policy and cookie policy

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