Hello,

From what I understand, a standard CCK field will not display it's label within a node if the field is empty. I think this a default behavior and does not have anything to do with any display settings.

However,, if the view to be inserted into a viewfield is empty within a node, the CCK field display is still "constructed" (divs rendered to contain the view fields, even though they are just empty), which also means that the label is shown even though the field is empty. This is a little confusing from a UI point of view.

I've tried adjusting some of the view settings, etc, but I can't seem to get the label to hide itself when the view is empty. I hope I am not missing something obvious. I searched the issue queue, but have not seen anything addressing this.

Is there a way to hide the field label dynamically? Can this only be accomplished via some theme-level pre-processing?

Cheers!
Ryan

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

rjacobs’s picture

Title: Possible to Hide Field Label if View is Empty » is it Possible to Hide Field Label if View to be insertied is Empty?

Edit: clarify title

rjacobs’s picture

Title: is it Possible to Hide Field Label if View to be insertied is Empty? » is it Possible to Hide Field Label if View to be inserted is Empty?

Well, I figure that I'll make a note about the "quick-fix" solution that I found. Basically, I placed a small conditional check at the theme level within a CCK field template file.

My viewfield is called "field_supported_services" so I copied over the base field template file "content-field.tpl.php" (from the CCK module themes folder) into my theme and then made a copy called "content-field-field_supported_services.tpl.php". Then, I made a small edit to this "content-field-field_supported_services.tpl.php" file to add a rudimentary conditional check to see if the view is "empty" (and if so, not display anything). I simply changed (starting around line 28):

 if (!$field_empty) : 
.... print label and field(s) ....
endif; 

to be:

 if (!$field_empty && stristr($items[0]['view'], '<div class="view-content">')) :
.... print label and field(s) ....
endif; 

Basically, I discovered that if the view was "empty", the field would be constructed, but the "view-content" div would not be. So it's absence is a simple indicator that this instance of the viewfield is an empty view.

I'm still convinced there is a better way to do this, and wonder if it makes sense to have some logic in the viewfield module itself? Still, that said, I think I can see why this would not be totally straightforward. It looks like viewfield really only "injects" the view into a field (and all the elements that ultimately appear are somewhat beyond its control... that's really dependent on the views module). So even an empty view will still have some wrapper divs around it (it's not totally "empty" data).

I guess I'm not really sure what the "graceful" way to check for an "empty" view would be...

Anyway, I hope this info is useful to someone, or that someone will be able to tell me a better way to do this.

Cheers,
Ryan

RedRat’s picture

I really want to see this bug corrected!

Now I am using Header field in my views instead of Viewfield's one, but it's a workaround, not a solution.

RedRat’s picture

Title: is it Possible to Hide Field Label if View to be inserted is Empty? » Is it Possible to Hide Field Label if View to be inserted is Empty?
Version: 6.x-1.x-dev » 6.x-1.0
rjacobs’s picture

Yeah, it would seem that some logic could be added to the module itself to check if the view returns any results. The theme-level solution I used depends on checking the final view markup, which is not ideal of course. I suppose checking the actual view variables directly would make the most sense.

elektrorl’s picture

Would love to see this bug fixed !

elektrorl’s picture

I think we may find a solution inside the file viewfield.theme.inc inside viewfield module near line 112.

function theme_viewfield_select($element) {
  if (!empty($element['#children'])) {
    $field = $element['#field_info'][$element['#field_name']];
    if ($field['multiple'] && $element['#delta'] == 0) {
      // This is needed only for multiple viewfields.
      drupal_add_css(drupal_get_path('module', 'viewfield') .'/theme/viewfield.css');
    }
    return '<div class="viewfield-select">'. $element['#children'] .'</div>';
  }
}

I'm a noob in php… So please help us!

RedRat’s picture

No, a real checking for field emptiness performed in the CCK module, in the 2390th line of content.module file. If $field_empty is set, the label of field is not diplayed.

rjacobs’s picture

Category: support » bug
Status: Active » Needs review
FileSize
791 bytes

Well, as elektrorl pointed out, viewfield.theme.inc was a good place to start looking. Also as RedRat noted, cck has a mechanism that sets a variable ($field_empty) when a field is empty (which the template uses to toggle the label on or off). So it seems to me that the trick is to get viewfield to just nullify it's output if the view returns no result, and thus hide the other wrapper markup that an empty view would normally produce, from cck. With an empty output, cck should catch the fact that the field us empty and set $field_empty to true.

The attached patch attempts to do this. I've only tested it on one site instance, but so far so good....

Cheers,
Ryan

RedRat’s picture

The 'call_user_func_array' call is VERY slow, so maybe it worth to call it once, something like:

     array_unshift($view_args, $view_name, $display);
     $output = call_user_func_array('views_embed_view', $view_args);
+    if (!stristr($output, '<div class="view-content">')) {
+        $output = NULL;
+    };
     // This node is "safe" again.

Can you check this code? It is a dirty hack, but it works for me.

rjacobs’s picture

Hi redrat,

In the patch I was using an added call_user_func_array to call function views_get_view_result simply to check if the view has a result. After this (but only if the result is true), the original module code uses call_user_func_array to call function views_embed_view to output the actual view markup.

I think the problem with checking the result of function views_embed_view is that it will not be empty even if the view has no result... it will still contain some wrapper divs and other view markup that's generated no matter what result the view returns. I think that passing this result to cck means it thinks there is something to display (even though it's just a bunch of empty wrapper divs), and it will therefore still generate the labels, etc...

I could be wrong (I'm certainly no expert in the actual code under the hood of either cck or views), but this logic has proven fruitful so far in my test case. Did the patch apply correctly for you? Did you clear all your caches and such?

I wonder if there are cases where views_get_view_result could return something even when the view has no fields/nodes to list?

Ryan

RedRat’s picture

> I think the problem with checking the result of function views_embed_view is that it will not be empty even if the view has no result...

Exactly. Because views always renders output with $classes string (defined in views-view.tpl.php file and used in standard views templates) even for empty results. So Viewfield module really have to check the view for emptyness before passing results to CCK.

P.S. I just messed up a bit my templates, but now your (and mine) patch works flawlessly. I think, maintainer should include your patch into the next release.

rjacobs’s picture

Good stuff, glad it works now for you too Redrat.

I incorrectly read your suggested code in #10, and yes, as far as I can see your approach should work also. Actually I thought about doing exactly what you did, but then I noticed the views_get_view_result function and figured it was a more binary way to do the check. I doubt views will ever change the way the <div class="view-content"> markup is used, but I just felt making a logic decision based on the final markup was not ideal.

You mentioned that the 'call_user_func_array' is very slow. Do you really think it's a performance risk to use that twice? I have no sense of the performance factors here, so any insights are certainly valuable.

Ryan

elektrorl’s picture

Patch in #10 is working for me. I don't see performance issue here. Thanks a lot.

rjacobs’s picture

Hi elektrorl,

Did you mean you used the patch in #9 or the variation in #10? Just wanted to ask as they both use the same logic, but could have different performance characteristics.

Ryan

rjacobs’s picture

Looks like we have 2 others who can confirm this is working. I've also had success with this on a handful of sites that I'm rolling out. It's quite a small tweak so I'm wondering if everyone thinks it's alright to mark this as "reviewed and tested" (#9)?

Anyone else find this useful or have issues?

Cheers,
Ryan

keithm’s picture

Title: Is it Possible to Hide Field Label if View to be inserted is Empty? » Produce output only for nonempty view
Version: 6.x-1.0 » 6.x-2.x-dev
FileSize
683 bytes

Please try this patch. Please note it's written for version 6.x-2.x.

sun’s picture

Status: Needs review » Reviewed & tested by the community

Didn't test it, but looks good to me.

keithm’s picture

WorldFallz’s picture

Status: Fixed » Active

This may or may not be intended behavior, but this fix doesn't print the empty text or the header if the 'display even when empty' option is checked.

Right now, the only thing I have available for empty / header text is a global text area so I changed my theme function to:

if ($view->result) {
  $output = $view_output;
} else {
  if (!empty($view->display[$view->current_display]->display_options['empty']) {
    $output = $view->display[$view->current_display]->display_options['empty']['area']['content'];
  } 
  if ($view->display[$view->current_display]->display_options['header']['area']['empty'] = 1) {
    $output .= $view->display[$view->current_display]->display_options['header']['area']['content'];
  }
}

This gets me to functionality equivalent to views, but it's dang ugly and most likely incorrect to do it this way. Not sure what the 'right' answer is.

keithm’s picture

@WorldFallz: I can reproduce your problem but the my views data structure looks slightly different than the one you seem to be working with. What version of views are you using? I tested with the latest release 6.x-2.12.

WorldFallz’s picture

Ah... good question, I forgot to include that. I'm using the latest dev of views 6.x-3.x.

keithm’s picture

Category: bug » feature

As you say, the approach is ugly and possibly incorrect, plus the views data structure changed from 2.0 to 3.0. Adapted for the two versions, this is the closest I got:

$view_output = $view->preview($display, $view_args);
// Check to make sure views returned real content so we don't produce
// just wrapper divs containing no content.
switch (floor(views_api_version())) {
  case 2.0:
    $header_display = $view->display[$display]->display_options['header_empty'];
    $footer_display = $view->display[$display]->display_options['footer_empty'];
    $empty_display = !empty($view->display[$display]->display_options['empty']);
    break;
  default:
    $header_display = $view->display[$display]->display_options['header']['text']['empty'];
    $footer_display = $view->display[$display]->display_options['footer']['text']['empty'];
    $empty_display = !empty($view->display[$display]->display_options['empty']['text']['content']);
    break;
}

if ($view->result || $header_display || $footer_display || $empty_display) {
  $output = $view_output;
}

Not exactly an elegant reliable solution.

I have rolled back the commit from #19 and changing this back to a feature request.

WorldFallz’s picture

at least it's a theme function, so it's easily overridden on an as needed basis. i just have no clue what the 'right' answer is.

geek-merlin’s picture

sub

WorldFallz’s picture

fyi the problem is still there (the label prints for empty views)-- the code has changed some (there is no theme directory-- the theme function is now in the .module file).

this is what I'm using now as an override:

function theme_viewfield_formatter_default($element) {
  // $_viewfield_stack keeps a record of the current node to prevent infinite
  // recursion during the view rendering process.
  global $_viewfield_stack;

  $node = $element['#node'];

  if (!empty($element['#item']['vname']) && !isset($_viewfield_stack[$node->nid])) {
    // Push id of current node unless it's a new node being previewed.
    if ($node->nid) {
      $_viewfield_stack[$node->nid] = $node->nid;
    }

    list($view_name, $display) = explode('|', $element['#item']['vname'], 2);
    $view_args = _viewfield_get_view_args($element['#item']['vargs'], $element['#node']);


    // Render the view like Views would do.
    // @see views_embed_view()
    $view = views_get_view($view_name);
    if ($view && $view->access($display)) {
      // Override the view's path to the current path. Otherwise, exposed views
      // filters would submit to the front page.
      $view->override_path = $_GET['q'];

      $output = $view->preview($display, $view_args);
    }

    // This node is "safe" again.
    if ($node->nid) {
      unset($_viewfield_stack[$node->nid]);
    }

    // Only return an actual view result to not break empty value behavior.
    if ($view->result) {
      return $output;
    } else {
      if (isset($view->display[$view->current_display]->display_options['empty'])) {
        return check_markup($view->display[$view->current_display]->display_options['empty']['area']['content'], $view->display[$view->current_display]->display_options['empty']['area']['format'], FALSE);
      }
      if ($view->display[$view->current_display]->display_options['header']['area']['empty'] = 1) {
        return check_markup($view->display[$view->current_display]->display_options['header']['area']['content'], $view->display[$view->current_display]->display_options['header']['area']['format'], FALSE);
      }
      if ($view->display[$view->current_display]->display_options['footer']['area']['empty'] = 1) {
        return check_markup($view->display[$view->current_display]->display_options['footer']['area']['content'], $view->display[$view->current_display]->display_options['footer']['area']['format'], FALSE);
      }
    }
  }
}

[edited to update the code for empty/header/footer]

SilviuChingaru’s picture

Status: Active » Closed (duplicate)

This is the same problem like in #477244: View field not working correctly with empty views..

To fix this in correct field API way, view should be executed in hook_field_prepare_view(), check if it has any output and if not unset that item because the field is empty (empty view).

Checkout this patch (it fix this problem also): https://drupal.org/node/477244#comment-7510777

I'll mark this as duplicate.

jimafisk’s picture

Issue summary: View changes

Thanks fiftyz! That thread fixed the missing exposed filters / no results behavior for me. Ended up applying patch at comment #56: https://www.drupal.org/node/477244#comment-12081410

I was seeing empty strings for $variables['empty'] and $variables['exposed'] in hook_preprocess_views_view() whenever no results were returned given the current filter values. Works great now!