Repository: sveltejs/svelte (JavaScript)
Date: 2018-04-29 13:48:30+00:00
Task type: Bug Fix

Issue:
`await` loses access to outer `each` variable
```html
{{#each items as item}}
	{{#await item.data}}
		<p>{{item.title}}: Loading...</p>
	{{then result}}
		<p>{{item.title}}: {{result}}</p>
	{{/await}}
{{/each}}

<script>
	export default {
		data() {
			return {
				items: [{
					title: 'Some data',
					data: Promise.resolve('this will never show up'),
				},
				{
					title: 'Some other data',
					data: Promise.resolve('this will never show up'),
				}]
			}
		}
	}
</script>
```
```
> TypeError: Cannot read property 'title' of undefined
```
[REPL](https://svelte.technology/repl?version=1.57.4&gist=be67adba829ee3d0ec569f2279820581)


Issue discussion:

Solution patch:
diff --git a/src/compile/nodes/AwaitBlock.ts b/src/compile/nodes/AwaitBlock.ts
--- a/src/compile/nodes/AwaitBlock.ts
+++ b/src/compile/nodes/AwaitBlock.ts
@@ -98,6 +98,8 @@ export default class AwaitBlock extends Node {
 		block.addVariable(promise);
 		block.addVariable(resolved);
 
+		block.maintainContext = true;
+
 		// the `#component.root.set({})` below is just a cheap way to flush
 		// any oncreate handlers. We could have a dedicated `flush()` method
 		// but it's probably not worth it
@@ -119,13 +121,12 @@ export default class AwaitBlock extends Node {
 				}
 			}
 
-			function ${handle_promise}(${promise}, ctx) {
+			function ${handle_promise}(${promise}) {
 				var ${token} = ${await_token} = {};
 
 				if (@isPromise(${promise})) {
 					${promise}.then(function(${value}) {
 						${this.value ? deindent`
-							var ctx = #component.get();
 							${resolved} = { ${this.value}: ${value} };
 							${replace_await_block}(${token}, ${create_then_block}, @assign(@assign({}, ctx), ${resolved}));
 						` : deindent`
@@ -133,7 +134,6 @@ export default class AwaitBlock extends Node {
 						`}
 					}, function (${error}) {
 						${this.error ? deindent`
-							var ctx = #component.get();
 							${resolved} = { ${this.error}: ${error} };
 							${replace_await_block}(${token}, ${create_catch_block}, @assign(@assign({}, ctx), ${resolved}));
 						` : deindent`
@@ -155,7 +155,7 @@ export default class AwaitBlock extends Node {
 				}
 			}
 
-			${handle_promise}(${promise} = ${snippet}, ctx);
+			${handle_promise}(${promise} = ${snippet});
 		`);
 
 		block.builders.create.addBlock(deindent`


Test patch:
diff --git a/test/runtime/samples/await-in-each/_config.js b/test/runtime/samples/await-in-each/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/await-in-each/_config.js
@@ -0,0 +1,31 @@
+let fulfil;
+
+let thePromise = new Promise(f => {
+	fulfil = f;
+});
+
+const items = [{
+	title: 'a title',
+	data: thePromise
+}];
+
+export default {
+	data: {
+		items
+	},
+
+	html: `
+		<p>a title: loading...</p>
+	`,
+
+	test(assert, component, target) {
+		fulfil(42);
+
+		return thePromise
+			.then(() => {
+				assert.htmlEqual(target.innerHTML, `
+					<p>a title: 42</p>
+				`);
+			});
+	}
+};
\ No newline at end of file
diff --git a/test/runtime/samples/await-in-each/main.html b/test/runtime/samples/await-in-each/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/await-in-each/main.html
@@ -0,0 +1,7 @@
+{#each items as item}
+	{#await item.data}
+		<p>{item.title}: loading...</p>
+	{:then result}
+		<p>{item.title}: {result}</p>
+	{/await}
+{/each}
\ No newline at end of file