eozzy
eozzy

Reputation: 68680

Separating start and end tags for conditional rendering

<template>
    <div>
        <template v-if="isFieldsetElement">
            <fieldset>
                <legend>Label Here</legend>
        </template>
        <template v-else>
            <label>Label Here</label>
        </template>

        <span> Description </span>
        <img src="image.png" />
        <div>more stuff here </div>

        <template v-if="isFieldsetElement">
            </fieldset>
        </template>
    </div>
</template>

I'm unable to do this tag separation. Basically I have a separate header and footer (for the lack of better word) but I can't do this in Vue like its possible in server-side generated markup.

Is there a workaround or a more elegant solution for this issue?

Upvotes: 1

Views: 1018

Answers (3)

eozzy
eozzy

Reputation: 68680

Using Dynamic Components:

<component :is="isFieldsetElement ? 'fieldset' : 'div'">
    <component :is="isFieldsetElement ? 'legend' : 'label'">
        <span> Description </span>
        <img src="image.png" />
        <div>more stuff here </div>
    </component>
</component>

Upvotes: 3

Nick Wang
Nick Wang

Reputation: 624

The output for PHP is a string, so you can set it like '' + 'hello' + '', but for JS framework, them used HTMLElement, so you can't do same thing here. I think you need to get used to using the component, also PHP. Example:

<?php
class View() {
   public $header; public $footer; public $content;
}
$view = new View(); $view->header = 'Hello';...
?>
<html>
  <body>
     <header>
       <?php echo $view->header?>
     </header>
     <div id="root">
       <?php echo $view->content?>
     </div>
     <footer>
       <?php echo $view->footer?>
     </footer>
  </body>
</html>

For above source, header, footer, content both mean one component, and the content usually has many child component.

So, tag separation never a good solution, include PHP template.

<template>
    <div>
        <template v-if="isFieldsetElement">
            <fieldset>
                <legend>Label Here</legend>
                <span> Description </span>
                <img src="image.png" />
                <div>more stuff here </div>
            </fieldset>
        </template>
        <template v-else>
            <label>Label Here</label>
            <span> Description </span>
            <img src="image.png" />
            <div>more stuff here </div>
        </template>
    </div>
</template>

or the other way same as your did in php:

var app = new Vue({data:{html:'<div>Hello</div>'}});
<template v-html="html"></template>

Upvotes: 1

Phil
Phil

Reputation: 164832

I'm unable to do this tag separation

That's right because Vue works with a complete document model so you cannot put together elements by parts

I'd go with a custom wrapping component. Something like...

<template>
  <div> <!-- single root element required -->
    <fieldset v-if="wrap">
      <legend>{{ label }}</legend>
      <slot></slot>
    </fieldset>
    <template v-else>
      <label>{{ label }}</label>
      <slot></slot>
    </template>
  </div>
</tenmplate>

<script>
export default {
  name: 'FieldWrapper',
  props: {
    wrap: Boolean,
    label: String
  }
}
</script>

and use it like

<FieldWrapper :wrap="isFieldsetElement" label="Label Here">
  <span> Description </span>
  <img src="image.png" />
  <div>more stuff here </div>
</FieldWrapper>

There's a little repetition of the <slot> within the component but for your use-case, I'd say that's acceptable.

JSFiddle Demo

Upvotes: 1

Related Questions