Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot bind attributes to direct children of data-wp-each #60981

Closed
danielpost opened this issue Apr 23, 2024 · 4 comments
Closed

Cannot bind attributes to direct children of data-wp-each #60981

danielpost opened this issue Apr 23, 2024 · 4 comments
Labels
[Feature] Interactivity API API to add frontend interactivity to blocks. [Type] Bug An existing feature does not function as intended

Comments

@danielpost
Copy link

danielpost commented Apr 23, 2024

Description

When binding an attribute using data-wp-bind to a direct child of a data-wp-each loop, you get the following errors:

hooks.tsx:272 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'classes')
    at hooks.tsx:272:50
    at Array.forEach (<anonymous>)
    at hooks.tsx:272:20
    at hooks.tsx:288:17
    at directives.js:361:20
directives.js:403 Uncaught TypeError: Cannot use 'in' operator to search for 'aria-expanded' in null
    at directives.js:403:7
    at Object.__ (utils.js:112:11)
    at at (hooks.module.js:1:3307)
    at Array.forEach (<anonymous>)
    at ut (hooks.module.js:1:2120)

It does seem to bind the attribute correctly, but any interactivity is broken.

Step-by-step reproduction instructions

Minimal example to reproduce the issue:

<?php
$context = [
	'items' => [
		[
			'id'      => 1,
			'title'   => 'Hello World',
			'classes' => 'class1 class2',
		],
		[
			'id'      => 2,
			'title'   => 'Hi World',
			'classes' => 'class1 class2',
		],
	],
];
?>

<div
	<?php echo wp_interactivity_data_wp_context( $context ); ?>
	data-wp-interactive="example"
>
	<template data-wp-each="context.items" data-wp-each-key="context.item.id">
		<div data-wp-bind--class="context.item.classes">
			<span data-wp-text="context.item.title"></span>
		</div>
	</template>
</div>

Screenshots, screen recording, code snippet

No response

Environment info

  • WP 6.5
  • Problem occurs without Gutenberg as well as with the latest version (18.1.2)
  • Chrome, macOS

Please confirm that you have searched existing issues in the repo.

Yes

Please confirm that you have tested with all plugins deactivated except Gutenberg.

Yes

@danielpost danielpost added the [Type] Bug An existing feature does not function as intended label Apr 23, 2024
@Mamaduka Mamaduka added the [Feature] Interactivity API API to add frontend interactivity to blocks. label Apr 23, 2024
@michalczaplinski
Copy link
Contributor

I can confirm the issue on my side as well.

@michalczaplinski
Copy link
Contributor

I wasn't able to debug this effectively. This was my minimal repro block:

// render.php
<?php

$context = [
	'items' => [
		[
			'id'      => 1,
			'title'   => 'One',
			'classes' => 'class1',
			'is1' 		=> true,
		],
		[
			'id'      => 2,
			'title'   => 'Two',
			'classes' => 'class2',
			'is2' 		=> true,
		],
	],
];
?>

<template data-wp-each="context.items" data-wp-each-key="context.items.id">
	<div data-wp-bind--class="context.item.classes">
		<span data-wp-text="context.item.title"></span>
	</div>
</template>

I was able to establish that the context is being reset incorrectly somewhere around those lines:

setScope( scope );
for ( const directiveName of currentPriorityLevel ) {
const wrapper = directiveCallbacks[ directiveName ]?.( directiveArgs );
if ( wrapper !== undefined ) {
props.children = wrapper;
}
}
resetScope();

setScope( scope );
const value = resolve( path, namespace );
const result = typeof value === 'function' ? value( ...args ) : value;
resetScope();

It seems that the directives are run twice and on the second run the context.items.classes is not set correctly anymore. Instead, of the context of the individual item, Preact sees the context.items.

cc @DAreRodz @cbravobernal

@michalczaplinski
Copy link
Contributor

I was going to try to fix this issue, but I can't reproduce it anymore.

This is the code that I used:

<!--  render.php -->

<?php
$context = [
	'items' => [
		[
			'title'   => 'One',
			'classes' => 'class1',
		],
		[
			'title'   => 'Two',
			'classes' => 'class2',
		],
	],
];
?>

<div
	<?php echo wp_interactivity_data_wp_context( $context ); ?>
	data-wp-interactive="repro/60981"
>

	<style> .class1 { color: red; } .class2 { color: blue } </style>

	<template data-wp-each="context.items" data-wp-each-key="context.item.id">
		<div data-wp-bind--class="context.item.classes">
			<span data-wp-text="context.item.title" data-wp-bind--id="context."></span>
			<button data-wp-on--click="actions.inc" data-wp-text="state.count"> </button>
		</div>
	</template>
</div>
// view.js
import { store, getContext } from "@wordpress/interactivity";

const { state } = store("repro/60981", {
  state: {
    count: 0,
  },
  actions: {
    inc: () => {
      state.count++;
    },
  },
});

Result:

Screen.Recording.2024-07-11.at.16.54.57.mov

@danielpost Please let me know if the problem still persist for you and share your reproduction if possible! Otherwise, I will close this issue as resolved, thanks!

@michalczaplinski
Copy link
Contributor

I'm going to close this issue as the problem cannot be reproduced anymore. Feel free to open a new one if it re-appears!

@michalczaplinski michalczaplinski closed this as not planned Won't fix, can't repro, duplicate, stale Jul 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Interactivity API API to add frontend interactivity to blocks. [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

No branches or pull requests

3 participants