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

Notification on subsequent DOM updates (not just the first) #3534

Closed
ryan-d-williams opened this issue Sep 13, 2024 · 22 comments
Closed

Notification on subsequent DOM updates (not just the first) #3534

ryan-d-williams opened this issue Sep 13, 2024 · 22 comments

Comments

@ryan-d-williams
Copy link
Contributor

Based on the documentation and by taking a look at the source code, right now the MODULE_DOM_CREATED notification is fired when the module is first loaded. Subsequent calls to updateDom do not fire any event.

I think it would be very beneficial to add a notification for each time the DOM is updated. I am currently accomplishing this in a vary hacky way, but it would be nice to add a notification to know exactly when the DOM update is complete so the module can interact with the new DOM if necessary.

My proposal is to add MODULE_DOM_UPDATED as a notification that fires when calls to updateDom are made.

The same code that is used to send the MODULE_DOM_CREATED notification is also used during updateDom, so the code changes will be minimal.

I'm happy to submit a PR for this change, but wanted to discuss it here first.

@sdetweil
Copy link
Collaborator

sdetweil commented Sep 13, 2024

who is updating your dom except you???

this was just the system letting you know that SOMETIME after your first getDom() return the content is IN the DOM so if you

use getDocumentBy????? they would be there

BEFORE the first notification , they are NOT in the dom..

this notification helps you by not having to set a timer for unknown length, or repeat checking

@sdetweil
Copy link
Collaborator

sdetweil commented Sep 13, 2024

calls to updateDom are syncronous in that they call getDom() or getTemplateData() before returning.. (after the specified delay. if any)

the problem on the 1st is YOU didn't call updateDom().

@ryan-d-williams
Copy link
Contributor Author

ryan-d-williams commented Sep 13, 2024

@sdetweil thank you for your response and for looking into this with me!

If the expectation is that updateDom is synchronous, then I believe there is a bug. See this example:

this.updateDom(0);
console.log("Just after updateDom");
console.log(document.getElementsByClassName("table-wrapper"))

setTimeout(() => {
    console.log("500ms Delay");
    console.log(document.getElementsByClassName("table-wrapper"))
}, 500)

If updateDom was synchronous, it would be expected that both of those log statements would return the same thing (since the content should be rendered after updateDom). However, they do not return the same thing:

image

This means that there is some unspecified delay after updateDom before the content is on the screen. Note that this is the same result even if updateDom is awaited.

I agree that if updateDom is synchronous, then there is not a need for MODULE_DOM_UPDATED, but it does not appear to be designed as synchronous our behaving synchronously. I think once it is determined how that function is expected to behave will determine the next steps. If it is expected to be synchronous then there is a bug. If it is expected to be async then MODULE_DOM_UPDATED will be useful.

Thanks again for your reply!

@sdetweil
Copy link
Collaborator

yeh, looking at the code that was added for the transitions its become async, and not await able,
so now your problem appears

@ryan-d-williams
Copy link
Contributor Author

That's what I'm seeing too.

So it seems as though adding in the MODULE_DOM_UPDATED is a simple change to ensure the module can still know when the DOM is updated without having to update that entire function stack to make it synchronous. I did a quick test and was able to add this notification using only a few extra lines (in the same manner that MODULE_DOM_CREATED is already emitted).

Should I go ahead with a PR so we can all see the potential changes?

@sdetweil
Copy link
Collaborator

i would

@sdetweil
Copy link
Collaborator

i wonder how many modules use this notification incorrectly

@ryan-d-williams
Copy link
Contributor Author

Which notification are you referring to? I think MODULE_DOM_CREATED is emitted correctly (but only emitted once). Is there a chance modules are using it incorrectly currently?

@sdetweil
Copy link
Collaborator

yes, we have unknown skill developers.

@ryan-d-williams
Copy link
Contributor Author

Good point. Once I get the PR submitted I can work on a PR for the docs to make this new notification known and the old one more explicit.

@sdetweil
Copy link
Collaborator

@KristjanESPERANTO what would it take to use the module list to scan for this notification literal

ryan-d-williams added a commit to ryan-d-williams/MagicMirror that referenced this issue Sep 13, 2024
…ed. Ensures the module can know when the DOM is available for interaction. Fixes MagicMirrorOrg#3534.
@KristjanESPERANTO
Copy link
Contributor

KristjanESPERANTO commented Sep 13, 2024

@sdetweil I can search for strings in all modules relatively easily. These modules are containing the string MODULE_DOM_CREATED:

  1. EXT-Pages: if (notification === "MODULE_DOM_CREATED") {
  2. internet-monitor: if (notification === "MODULE_DOM_CREATED") {
  3. MMM-anotherNewsFeed: if (notification === "MODULE_DOM_CREATED" && this.config.hideLoading) {
  4. MMM-BlaguesAPI: if (notification === 'MODULE_DOM_CREATED') {
  5. MMM-CalendarExt3Agenda: if (notification === 'MODULE_DOM_CREATED') {
  6. MMM-Carousel: if (notification === "MODULE_DOM_CREATED") {
  7. mmm-dropbox: if (notification === 'MODULE_DOM_CREATED') {
  8. MMM-Markdown: if (notification === 'MODULE_DOM_CREATED') {
  9. MMM-MercedesMe: else if (notification === 'MODULE_DOM_CREATED') {
  10. MMM-MeteoFrance: case "MODULE_DOM_CREATED":
  11. MMM-MPRIS2-WebSocket: if (notification == "MODULE_DOM_CREATED") {
  12. MMM-MusicButler: if (notification === "MODULE_DOM_CREATED" && this.config.hideLoading) {
  13. MMM-neoomAPI: if (notification === 'MODULE_DOM_CREATED') {
  14. MMM-OnThisDay: if (notification === 'MODULE_DOM_CREATED') { and module.notificationReceived('MODULE_DOM_CREATED');
  15. MMM-Page-Selector: }else if(notification === "MODULE_DOM_CREATED"){
  16. MMM-PlexNowPlaying: case "MODULE_DOM_CREATED":
  17. MMM-RandomPhoto: if (notification === "MODULE_DOM_CREATED") {
  18. MMM-RemoteCompliments: if (notification === "MODULE_DOM_CREATED") {
  19. MMM-Speedway: if (notification === 'MODULE_DOM_CREATED') {
  20. MMM-Tronity: else if (notification === 'MODULE_DOM_CREATED') {
  21. MMM-Wallpaper: if (notification === "MODULE_DOM_CREATED" && self.config.userPresenceAction === "show") {
  22. MMM-WiFiPassword: case "MODULE_DOM_CREATED":
  23. MMM-YouTubeWebView: if (notification == 'MODULE_DOM_CREATED') {

I do not yet understand how to recognize whether this notification could be used incorrectly. If this is easy, maybe I could add a check for it in the list.

@sdetweil
Copy link
Collaborator

after use is harder, if the module used document.getElementsBy... functions then its possible they could be impacted

if not then no impact

@sdetweil
Copy link
Collaborator

i should have also added! NICE that you can search!!!

@ryan-d-williams
Copy link
Contributor Author

I'm not sure if it is possible to detect incorrect usage using static analysis only.

For example, a module could use getElementsBy... or getElementBy... and still use the MODULE_DOM_CREATED correctly (for example if they never call updateDom or if they only care about the first time the DOM was rendered).

You would have to able to determine that the module 1. Calls updateDom and 2. Intends to see the re-render via MODULE_DOM_CREATED. I don't think you can detect both of those conditions statically.

I also don't think we need to detect this condition. If a user was using it incorrectly, their module simply wouldn't work (they would be waiting for a notification that never arrives).

@KristjanESPERANTO
Copy link
Contributor

Okay, thank you both for the explanation 🙂 I drop the idea of trying to check this.
At least you have now an overview of how many modules use this notification. Feel free to let me know if you have similar questions in the future.

@sdetweil
Copy link
Collaborator

sdetweil commented Sep 13, 2024

well, can you do another or nested search

search those modules for

document.getElementsby

only care about the ones that have it

@ryan-d-williams
Copy link
Contributor Author

@sdetweil even with a nested search, there are still many ways those two things can be nested and still be used correctly.

If I wait for the MODULE_DOM_CREATED notification, it just means the DOM has been rendered the first time. I can safely use document.getElementsBy... or any other variation.

The danger would be if I tried to use a combination of updateDom and MODULE_DOM_CREATED assuming that the latter was fired on a DOM re-render. But since there are valid reasons to use this notification, I don't think it's possible to determine it is being used incorrectly by string search (you need to understand the intent of it).

For example, a module can use MODULE_DOM_CREATED to do something on the first render, and then later on call updateDom without caring what happens on the re-render and both of those are independently safe operations. Any nested string search would flag this safe operation.

@sdetweil
Copy link
Collaborator

sdetweil commented Sep 13, 2024

doah.. true

@sdetweil
Copy link
Collaborator

as you are proposing a new notification and not overloading the old, it doesn't matter

khassel pushed a commit to ryan-d-williams/MagicMirror that referenced this issue Sep 13, 2024
…ed. Ensures the module can know when the DOM is available for interaction. Fixes MagicMirrorOrg#3534.
khassel pushed a commit that referenced this issue Sep 18, 2024
…via `updateDom` (#3535)

- [x] Base your pull requests against the `develop` branch.
- [x] Include these infos in the description:
> - Does the pull request solve a **related** issue?
Yes - solves #3534

> - If so, can you reference the issue like this `Fixes
#<issue_number>`?
Fixes #3534 (also mentioned in commit message)

> - What does the pull request accomplish? Use a list if needed.

> > - Adds a new notification (`DOM_OBJECTS_UPDATED`) when the DOM is
updated via `updateDom`

- [x] Please run `npm run lint:prettier` before submitting
- [x] Don't forget to add an entry about your changes to the
CHANGELOG.md file.

More info can be found in #3534, but as a summary:

The `updateDom` function is not synchronous - there is an undetermined
amount of time between when it completes and when the DOM has actually
been re-rendered and is ready for interaction. The existing notification
(`MODULE_DOM_CREATED`) only fires once on the initial DOM render. This
PR solves the issue of subsequent re-renders by adding a new
notification that fires whenever the DOM is ready after an update. This
notification falls within expected lifecycle notifications (very similar
to other libraries that provide DOM lifecycle notifications).
@ryan-d-williams
Copy link
Contributor Author

@sdetweil @khassel @rejas

Sorry to rehash this... while I was submitting a PR for the doc update, I realized that my choice of notification name was not ideal.

Given the 3 current notifications (ALL_MODULES_STARTED, DOM_OBJECTS_CREATED, MODULE_DOM_CREATED), it would make much more sense for this new notification to be MODULE_DOM_UPDATED instead of the current DOM_OBJECTS_UPDATED since the update is only for the requesting module and is only sent to one module.

I went ahead and added a new commit/PR. Let me know if you have any thoughts or feedback.

@sdetweil
Copy link
Collaborator

good catch. i agree

rejas pushed a commit that referenced this issue Sep 19, 2024
…_UPDATED` (#3548)

This is an update to #3535. See #3534 for discussion and context. Fixes
#3534 (again).
khassel added a commit that referenced this issue Sep 30, 2024
## [2.29.0] - 2024-10-01

Thanks to: @bugsounet, @dkallen78, @jargordon, @khassel,
@KristjanESPERANTO, @MarcLandis, @rejas, @ryan-d-williams, @sdetweil,
@skpanagiotis.

> ⚠️ This release needs nodejs version `v20` or `v22`, minimum version
is `v20.9.0`

### Added

- [compliments] Added support for cron type date/time format entries mm
hh DD MM dow (minutes/hours/days/months and day of week) see
https://crontab.cronhub.io for construction (#3481)
- [core] Check config at every start of MagicMirror² (#3450)
- [core] Add spelling check (cspell): `npm run test:spelling` and handle
spelling issues (#3544)
- [core] removed `config.paths.vendor` (could not work because `vendor`
is hardcoded in `index.html`), renamed `config.paths.modules` to
`config.foreignModulesDir`, added variable `MM_CUSTOMCSS_FILE` which -
if set - overrides `config.customCss`, added variable `MM_MODULES_DIR`
which - if set - overrides `config.foreignModulesDir`, added test for
`MM_MODULES_DIR` (#3530)
- [core] elements are now removed from `index.html` when loading script
or stylesheet files fails
- [core] Added `MODULE_DOM_UPDATED` notification each time the DOM is
re-rendered via `updateDom` (#3534)
- [tests] added minimal needed node version to tests (currently v20.9.0)
to avoid releases with wrong node version info
- [tests] Added `node-libgpiod` library to electron-rebuild tests
(#3563)

### Removed

- [core] removed installer only files (#3492)
- [core] removed raspberry object from systeminformation (#3505)
- [linter] removed `eslint-plugin-import`, because it doesn't support
ESLint v9. We will reenter it later when it does.
- [tests] removed `onoff` library from electron-rebuild tests (#3563)

### Updated

- [weather] Updated `apiVersion` default from 2.5 to 3.0 (#3424)
- [core] Updated dependencies including stylistic-eslint
- [core] nail down `node-ical` version to `0.18.0` with exception
`allow-ghsas: GHSA-8hc4-vh64-cxmj` in `dep-review.yaml` (which should
removed after next `node-ical` update)
- [core] Updated SocketIO catch all to new API
- [core] Allow custom modules positions by scanning index.html for the
defined regions, instead of hard coded (PR #3518 fixes issue #3504)
- [core] Detail optimizations in `config_check.js`
- [core] Updated minimal needed node version in `package.json`
(currently v20.9.0) (#3559) and except for v21 (no security updates)
(#3561)
- [linter] Switch to ESLint v9 and flat config and replace
`eslint-plugin-unicorn` by `@eslint/js`
- [core] fix discovering module positions twice after #3450

### Fixed

- Fixed `checks` badge in README.md
- [weather] Fixed issue with the UK Met Office provider following a
change in their API paths and header info.
- [core] add check for node_helper loading for multiple instances of
same module (#3502)
- [weather] Fixed issue for respecting unit config on broadcasted
notifications
- [tests] Fixes calendar test by moving it from e2e to electron with
fixed date (#3532)
- [calendar] fixed sliceMultiDayEvents getting wrong count and
displaying incorrect entries, Europe/Berlin (#3542)
- [tests] ignore `js/positions.js` when linting (this file is created at
runtime)
- [calendar] fixed sliceMultiDayEvents showing previous day without
config enabled

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: Michael Teeuw <[email protected]>
Co-authored-by: Kristjan ESPERANTO <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ross Younger <[email protected]>
Co-authored-by: Veeck <[email protected]>
Co-authored-by: Bugsounet - Cédric <[email protected]>
Co-authored-by: jkriegshauser <[email protected]>
Co-authored-by: illimarkangur <[email protected]>
Co-authored-by: sam detweiler <[email protected]>
Co-authored-by: vppencilsharpener <[email protected]>
Co-authored-by: veeck <[email protected]>
Co-authored-by: Paranoid93 <[email protected]>
Co-authored-by: Brian O'Connor <[email protected]>
Co-authored-by: WallysWellies <[email protected]>
Co-authored-by: Jason Stieber <[email protected]>
Co-authored-by: jargordon <[email protected]>
Co-authored-by: Daniel <[email protected]>
Co-authored-by: Ryan Williams <[email protected]>
Co-authored-by: Panagiotis Skias <[email protected]>
Co-authored-by: Marc Landis <[email protected]>
@khassel khassel closed this as completed Sep 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants