-
Notifications
You must be signed in to change notification settings - Fork 319
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
As a developer I would like to do sync actions on property changes #643
Comments
another usage example this.firstName = 'foo';
// fullName should be updated whenever firstName or lastName changes
if (this.fullName.contains('foo')) {
// do something
// never reached as fullName will only be updated in the next microtask if using `update`
} |
You could use the
|
hmmm using |
and you don't have access to component instance ( |
@daKmoR On the side of logging, to better inform the outcomes you hope to see in this request, can you explain how you see this as being different than a custom getter/setter?
In the context of your computed properties, it would seem that a getter would also provide much of what could be needed here:
In the above case the Maybe it's just boilerplate, or convention vs configuration, but whether those or something else I look forward to your thoughts here. |
does 'updated' fire too late for your purposes, @daKmoR ?
|
actually, this whole thing started while I was preparing a blog post about testing - and I wanted to have a simple example of how you can do an action on a property change. In my ignorance, I thought just log something that should be easy... oh boy was I wrong 🙈 That was the actual test I started out with. it('logs "We like cats too :)" if the value is set to "cat"', async () => {
const el = /** @type {A11yInput} */ (await fixture(html`
<a11y-input></a11y-input>
`));
const logSpy = sinon.spy(el, 'log');
el.value = 'cat';
expect(logSpy.callCount).to.equal(1);
}); So primarily it's not about logging - it was just an example. Depending on which type of logging you wanna do Why not a custom getter/setter?I would still like to use all the features of a property.
this of course works but I would need to redo all the attributes logic Why not just a getter?
ConclusionAs far as I can tell these are the hard requirements:
You can read the really long full story here - the link goes tot he relevant part where I discover the "issue": https://dev.to/open-wc/testing-workflow-for-web-components-g73#spying-on-code |
It seems like making |
AFAIK, yes |
what do you mean? rename _requestUpdate(name, oldValue) {
// _requestUpdate code then at the end
this.setProperty(name, oldValue);
} if yes then I (or someone) could prepare a PR for it 💪 |
@sorvell if you could give a hint on how it should look like I'm sure I could prepare a PR 🤗 |
Sorry, I was thinking just renaming `_requestUpdate` to `setProperty`. I
can't say for sure if this makes sense as I haven't really thought about it
much more, but we can iterate on the PR.
…On Sat, Apr 27, 2019 at 6:39 AM Thomas Allmer ***@***.***> wrote:
@sorvell <https://github.com/sorvell> if you could give a hint on how it
should look like I'm sure I could prepare a PR 🤗
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#643 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAATIK6IAJYLIOQK4JQGQX3PSRJPRANCNFSM4HECYBNA>
.
|
This covers my use case (i was overriding |
The best place to do this is in /**
* Called synchronously when a property has changed.
*/
protected propertyChanged(name: PropertyKey, oldValue?: unknown): void {}
private _requestUpdate(name?: PropertyKey, oldValue?: unknown) {
let shouldRequestUpdate = true;
// If we have a property key, perform property update steps.
if (name !== undefined) {
const ctor = this.constructor as typeof UpdatingElement;
const options =
ctor._classProperties!.get(name) || defaultPropertyDeclaration;
if (ctor._valueHasChanged(
this[name as keyof this], oldValue, options.hasChanged)) {
if (!this._changedProperties.has(name)) {
this._changedProperties.set(name, oldValue);
}
// Hook to allow synchronous property change observers.
this.propertyChanged(name, oldValue);
// Add to reflecting properties set.
// Note, it's important that every change has a chance to add the
// property to `_reflectingProperties`. This ensures setting
// attribute + property reflects correctly.
if (options.reflect === true &&
!(this._updateState & STATE_IS_REFLECTING_TO_PROPERTY)) {
if (this._reflectingProperties === undefined) {
this._reflectingProperties = new Map();
}
this._reflectingProperties.set(name, options);
}
} else {
// Abort the request if the property should not be considered changed.
shouldRequestUpdate = false;
}
}
if (!this._hasRequestedUpdate && shouldRequestUpdate) {
this._enqueueUpdate();
}
} |
Synchronous property change observers are useful in many cases, at least for me. Right now, I have to use custom setters to achieve that, which has a fair amount of boilerplate. |
So we also have fair amount of logic based on computed partial states in Polymer and decided to look into porting this behavior to Lit, in the form of https://github.com/Neovici/computing-lit-element It's not feature complete (no support for wildcards/paths) but it did make a sample component very convenient to migrate: Neovici/cosmoz-treenode@v3.0.1...v4.0.1#diff-4dfb1d30ec99074e5e06658034dd2775 The implementation is very compact (https://github.com/Neovici/computing-lit-element/blob/master/src/computingMixin.js#L43) and works like this: This all can be conveniently packaged in a mixin so the lit-elements that needs this functionality can just, well, mix it in. We are looking into doing the same for Hope this is useful for people ending up here :) |
@nomego The replacement for computed properties is getters. In cosmoz-treenode, it looks like every computed property can be replaced by a getter that accesses properties of |
@justinfagnani Well it can, I initially ported it like that, but there were two issues with it. First, given:
The second thing is that expensive getters gets mixed up with local properties, it's hard for a dev in a team to realize that For us, the porting of this functionality makes the transition a lot easier, the state a lot more clear, and we avoid the pitfalls of re-evaluating these things unnecessarily. |
This has been inactive for awhile, but we recently merged #959 which is at least related to this. In general we've chosen an asynchronous rendering model for LitElement because we think it sets up users for great performance out of the box. Rendering updates are naturally batched and occur before anything is painted to the screen. This does put a burden on the test environment, and this is one reason we've exposed the We've also recently landed the ability to customize LitElement's default property handling by specifying a custom property descriptor using |
Description
There is no public API that allows for sync actions like logging or "computed" properties.
Example use case:
Logging
We like cats too :)
whenever the propertymood
gets set tocat
.Live Demo
https://stackblitz.com/edit/lit-element-example-nkwdco?file=index.js
Expected Results
Actual Results (when using public API
update
)Code for reference:
Note
Workaround with _requestUpdate works but it's a private API.
Code for reference:
Versions
The text was updated successfully, but these errors were encountered: