Repository: sveltejs/svelte (JavaScript)
Date: 2017-05-04 13:34:41+00:00
Task type: Bug Fix

Issue:
{{Yield}} content isn't injected in the correct place
per docs https://svelte.technology/guide#yield-tags:
The button below appears ***above*** the yielded content instead of below it
```
<div class='modal'>
  {{yield}} <!-- content is injected here -->
  <button on:click='destroy()'>close modal</button>
</div>
```
{{Yield}} content isn't injected in the correct place
per docs https://svelte.technology/guide#yield-tags:
The button below appears ***above*** the yielded content instead of below it
```
<div class='modal'>
  {{yield}} <!-- content is injected here -->
  <button on:click='destroy()'>close modal</button>
</div>
```


Issue discussion:
This looks related to the changes in 1.18.0 for #3. It's a bit hard to tell what's going on the in REPL because there seem to be some other bugs in the REPL surfacing as I look at this. But I'm fairly certain the code being generated is actually wrong. The code creates the div and places the button in it:

```javascript
	var div_1 = createElement( 'div' );
	setAttribute( div_1, 'svelte-2785217407', '' );
	div_1.className = "modal";
	appendNode( createText( " \n\t" ), div_1 );
	var button = createElement( 'button' );
	appendNode( button, div_1 );
```

and then later mounts the `{{yield}}`ed component to that same div.

```javascript
			component._yield && component._yield.mount( div_1, null );
```

Things look okay if you wrap the `{{yield}}` in its own div, as we're then mounting the `{{yield}}`ed component to _that_ div.
[This](https://github.com/sveltejs/svelte/pull/512/files#diff-7fbf403915d6e02e04828c41781c0e79) looks like the change at fault. If the `{{yield}}` isn't the last sibling in its parent node, I don't see how we can get away without anchors here.
This looks related to the changes in 1.18.0 for #3. It's a bit hard to tell what's going on the in REPL because there seem to be some other bugs in the REPL surfacing as I look at this. But I'm fairly certain the code being generated is actually wrong. The code creates the div and places the button in it:

```javascript
	var div_1 = createElement( 'div' );
	setAttribute( div_1, 'svelte-2785217407', '' );
	div_1.className = "modal";
	appendNode( createText( " \n\t" ), div_1 );
	var button = createElement( 'button' );
	appendNode( button, div_1 );
```

and then later mounts the `{{yield}}`ed component to that same div.

```javascript
			component._yield && component._yield.mount( div_1, null );
```

Things look okay if you wrap the `{{yield}}` in its own div, as we're then mounting the `{{yield}}`ed component to _that_ div.
[This](https://github.com/sveltejs/svelte/pull/512/files#diff-7fbf403915d6e02e04828c41781c0e79) looks like the change at fault. If the `{{yield}}` isn't the last sibling in its parent node, I don't see how we can get away without anchors here.

Solution patch:
diff --git a/src/generators/dom/visitors/YieldTag.js b/src/generators/dom/visitors/YieldTag.js
--- a/src/generators/dom/visitors/YieldTag.js
+++ b/src/generators/dom/visitors/YieldTag.js
@@ -1,9 +1,11 @@
 export default function visitYieldTag ( generator, block, state ) {
-	block.builders.mount.addLine(
-		`${block.component}._yield && ${block.component}._yield.mount( ${state.parentNode || block.target}, null );`
+	const parentNode = state.parentNode || block.target;
+
+	( state.parentNode ? block.builders.create : block.builders.mount ).addLine(
+		`if ( ${block.component}._yield ) ${block.component}._yield.mount( ${parentNode}, null );`
 	);
 
 	block.builders.destroy.addLine(
-		`${block.component}._yield && ${block.component}._yield.destroy( detach );`
+		`if ( ${block.component}._yield ) ${block.component}._yield.destroy( detach );`
 	);
 }
\ No newline at end of file


Test patch:
diff --git a/test/runtime/samples/component-yield-placement/Modal.html b/test/runtime/samples/component-yield-placement/Modal.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-yield-placement/Modal.html
@@ -0,0 +1,6 @@
+<div class='modal-background' on:click='destroy()'></div>
+
+<div class='modal'>
+	{{yield}}
+	<button on:click='destroy()'>close modal</button>
+</div>
\ No newline at end of file
diff --git a/test/runtime/samples/component-yield-placement/_config.js b/test/runtime/samples/component-yield-placement/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-yield-placement/_config.js
@@ -0,0 +1,25 @@
+export default {
+	data: {
+		showModal: true
+	},
+
+	html: `
+		<div class='modal-background'></div>
+
+		<div class='modal'>
+			<h2>Hello!</h2>
+			<button>close modal</button>
+		</div>
+	`,
+
+	test ( assert, component, target, window ) {
+		const button = target.querySelector( 'button' );
+		const click = new window.MouseEvent( 'click' );
+
+		button.dispatchEvent( click );
+
+		assert.htmlEqual( target.innerHTML, `
+			<button>show modal</button>
+		`);
+	}
+};
diff --git a/test/runtime/samples/component-yield-placement/main.html b/test/runtime/samples/component-yield-placement/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-yield-placement/main.html
@@ -0,0 +1,15 @@
+{{#if showModal}}
+	<Modal on:destroy='set({ showModal: false })'>
+		<h2>Hello!</h2>
+	</Modal>
+{{else}}
+	<button on:click='set({ showModal: true })'>show modal</button>
+{{/if}}
+
+<script>
+	import Modal from './Modal.html';
+
+	export default {
+		components: { Modal }
+	};
+</script>
\ No newline at end of file