I created a component-based snippet inserting a picture with some properties like size, rounded corners, alignment left/right/center, etc. Now, when I insert multiple instances of this snippet on one page, all the snippets have the same property values! It looks like the snippets share the same component instance. Do you have any idea how to solve the issue?
That has something to do with how you are “injecting” the component properties into the page.
If you are doing it like described in this tip here Access component properties from a page or partial · October CMS Tricks, you make it impossible to use the same component twice, as you’ll override the same page variables with each instance.
I use public member variables on my components and __SELF__ ) Building CMS Components - October CMS - 3.x) on my implementations, altough only on the “top level”, meaning when rendering the component initially, not in partials further down the line.
Short example:
AComponent.php
use Cms\Classes\ComponentBase;
class AComponent extends ComponentBase
{
public string $title;
public string $content;
public function componentDetails(): array
{
return [
'name' => 'An example component',
'description' => 'Descriptions are hard'
];
}
public function defineProperties(): array
{
return [
'title' => [ ... ],
'content' => [....],
];
}
public function onRun()
{
$this->title = $this->property('title', 'A placeholder');
$this->content = $this->property('content', 'Placeholder content');
}
public function onRefreshContent()
{
$this->content = post('dynamic_content', 'This is very dynamic');
return $this->renderPartial('@content.htm', ['content' => $this->content]);
}
}
default.htm
<h3>{{ __SELF__.title }}</h3>
{% partial '@content.htm' content=__SELF__.content %}
<button data-request="onRefreshContent" data-request-data="{dynamic_content: 'This content is much better, because it is very dynamic'"}>Refresh content</button>
content.htm
{{ content }}
SELF can be used as an object to access the properties, and if cast into a string it gives back the alias of the component, which is very useful if you rely on IDs or need other data-attributes for distinguishing your components in the frontend.
Very hasty written, boiled down to the essentials and probably with some typos - but I hope it gets the concept through.
Unfortunately, it does not work for me. My components are not placed on the page directly. The component instances are snippets inserted in a markdown content like this
and the markdown content is placed on the page using
{{ content | md }}
When I place a breakpoint on the component’s init() method I see it’s called only once on the page. It looks like placing two same components on a page is not an issue, placing two same component-based snippets in one markdown content and then putting this content on a page instantiates the class only once.
Sorry, I’am not too familiar with that, but I think you need to have unique “data-snippet” codes.
I’ve just checked this with the Pages plugin (added a component, that is registered as a snippet, two times into a richeditor block, which should basically be the same scenario as your) and it automatically post-fixed the data-snippet property.
YES, this works. It would be nice to have the option to modify the snippet name in the Inspector because the Insert Snippet action in the markdown editor (not sure about richteditor, I assume the same behavior) does not modify the data-snippet property automatically. However, that’s another case.
These are 4 snippets of the same type (the same component), but each with different parameters… Who is who? In this case would be helpful to have a possibility of parametrized name ("Snippet name :param1 (:param2)") or something. (EDIT: This can be solved via CSS.)
And second one - in backend preview mode are all <figure> elements within WYSIWYG field displayed as white space only. I can cover it with custom CSS, but it would be better to have it in backend core.