-
-
Notifications
You must be signed in to change notification settings - Fork 924
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
Schedule an operation after redraw? #1837
Comments
It sounds like using |
@dwaltrip That would mean breaking up the flow into an additional function, some data flag to trigger the operation and additional data properties to keep the context of this function. A better option is a Promise with setTimeout. An even better option is for |
What does Normally, |
As mentioned in the chat, you can use an empty fragment with hooks to get a hook that fires after all the hooks of a given tree: {view(){ return [
m(tree),
m.fragment({onupdate(){}},[])
]}} |
@dwaltrip Yes, I am calling I figured something like @pygy suggested could work. But it'd be ugly. I simplified the example above, omitted (here irrelevant) contextual variables that should also be saved for the focus to be set correctly. If I don't get a Promise here:
I'd rather do something like: async function focusNextRow(e) {
let nextRowJq = getRowJq(e).next()
if (!nextRowJq.length) {
createNewRow()
m.redraw()
nextRowJq = getRowJq(e).next()
if (!nextRowJq.length) {
for (let i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 10))
nextRowJq = getRowJq(e).next()
if (nextRowJq.length) break
}
}
}
return focusTextInputInside(nextRowJq)
} This is much more legible, and much simpler. It is ugly though, and this would be much better: async function focusNextRow(e) {
let nextRowJq = getRowJq(e).next()
if (!nextRowJq.length) {
createNewRow()
await m.redraw()
nextRowJq = getRowJq(e).next()
}
return focusTextInputInside(nextRowJq)
} This is the reason for my request. |
Actually, my comment was meant to be posted in #1836, I mixed things up, sorry for the noise... As for your issue, you want to set the focus on a part of your app if it exists, and create a new field then set the focus on it otherwise, is it correct? Do you have keys on your items? |
@pygy Correct. I do. |
It makes things a bit trickier then, but still, there may be a way to do it all from the views, by marking the item that last had the focus in the model, and setting the focus on the next one on redraw (whether or not it exists at the point the previous one is marked). If it had been a non-keyed list, you could have relied on the traversal order of the nodes, but keyed lists may be traversed out of order by the render engine, so you'd need, on redraw, to mark the next/new item based on whether the previous in the list had the focus, and use Does that make sense? |
@andraaspar Here's an example of what I meant: |
Is there a reason the target input cannot be managed by mithril? Something like: var Component = {
oninit: function() {
this.dataRows = getDataRows();
},
createNewRow: function(params) {
var newRow = /* set up new row */;
this.dataRows.push(row);
},
view: function() {
var isInputReceivingFocus = /* conditions for this flag */;
var isTargetRow = (row) => /* determine if this is the target row */;
return m('div', [
this.dataRows.map(row => {
return m('input', {
type: 'text',
oncreate: function(vnode) {
if (isInputReceivingFocus && isTargetRow(row)) {
vnode.dom.focus(); // set the focus on the <input>, using DOM api on the actual element
}
}
});
})
])
}
} I'm not sure I fully understand the context and what you are trying to do. |
I'll note that this has been suggested before (way to run code after a redraw), including by me. |
Closing due to inactivity. |
It would seem natural for
m.redraw()
to return a promise that resolves after the redraw is completed – ie. the DOM is updated.Example use case:
The above function could be called from various event handlers, and manages focus as well as creates a new row when necessary.
The text was updated successfully, but these errors were encountered: