Closed richard-engineering closed 7 years ago
purchaseAmountEnabledLink.set(false);
console.log(purchaseAmountEnabledLink.value);
When you set the link, link.value should not change. As it will change some upper state, and link object will be recreated. Links themselves are immutable.
However, this code behaves not according to the logic you described. Look at the inline comments:
if (!enabled) { <- when new link value is false...
console.log("I am disabling thingy");
purchaseAmountEnabledLink.set(false); <- ...you set another link to false. Should it be vice versa?
console.log(purchaseAmountEnabledLink.value); // <- that's remains 'true' as links are immutable.
}
And onChange doesn't work with Input. It expects just valueLink or checkedLink.
Also, the behavior you described here seems to be close to the radio-buttons. There's an easier way to represent radio group state. In your case, just one boolean flag is enough.
https://github.com/Volicon/NestedLink#radio-groups-and-select-list
Also, there's another way of handling data cross-dependencies. You can apply pipe
to the componentLink function, and handle cross-dependencies inside of pipe's argument. In this case, there will be just one atomic update of the state (and one render) on checkbox click.
https://github.com/Volicon/NestedLink#-linkpipe-transform--any--any---link
Ah yes, I copied the wrong code over into the issue, was cleaning up the code to remove unnecessary things (I initially misunderstood what the use case was my coworker was having problems with and thought it was on uncheck, that was copied from older code that equally didn't work). No it's not radio buttons, we actually want to allow multiple selections (there are more than 2 checkboxes on the actual screen, I simplified the code considerably in the issue).
When you set the link, link.value should not change. As it will change some upper state, and link object will be recreated. Links themselves are immutable.
How come this doesn't work then? Is it something with React not propagating a change down then?
const firstEnabledLink = componentLink.at('first_checkbox_key').at('enabled')
.onChange((enabled) => {
console.log("I was hit", enabled);
if (enabled) {
console.log("I am disabling thingy");
secondLink.set(false);
console.log(secondLink.value); // Remains 'true'
}
});
...
<Input type='checkbox' checkedLink={firstEnabledLink}/>
Btw: thanks for the quick response Edit: Fixed misnamed link variable in example, it was not misnamed when I tested it (blame my editing of the code to make the example clearer)
Here, when you disable first checkbox, you're disabling the second one instead of enabling it.
if (!enabled) { // <- this condition should be flipped, I guess
console.log("I am disabling thingy");
purchaseAmountEnabledLink.set(false);
Ok, about pipe
. You could do it like this. Just do npm update
.
function checkboxRules( next, prev ){
if( next.first.enabled && !prev.first.enabled ){
next.second = { enabled : false };
}
...
return next;
}
const smartLink = componentLink.pipe( checkboxRules );
So, all of your rules will be checked and applied in a single place, and you will have one atomic UI update no matter how complex they are. You have to detect what have changed manually, though. Comparing next and prev.
That's just an alternative approach to the problem when you move these rules checking upper. Must result in cleaner code. Which is way easier to reason about.
Ahh, saw your commit a few minutes ago. Is next the old state and prev the new state? I suppose I can console.dir that. I think I understand your example after staring at it, will test and get back to you with any questions.
next is new state, prev is prev state. Whatever you return substitutes the next state.
Okay I've implemented a test file and with pipe behaves very strangely with Input from 'valuelink/tags', I'll upload it to a project in a bit so you can run it yourself and see.
https://github.com/rhan-mentad/valuelink-debug
(sorry about the cruft, was getting weird path errors trying to port over a smaller webpack config we use so I gave up and used the original boilerplate project as the base)
Do npm i
followed by npm start
, navigate to localhost:3001
.
Changes are in client/main.jsx
If you comment out the pipe command, the Input checkedLink functions fine. If the pipe command is in there then you cannot select the second checkbox after it gets deselected by clicking the first checkbox.
Nvm I think I was an idiot, mixed up old and new state in the callback. Everything works great for our use case. Thanks for the help :)
Okay, just for the case - I'm copying my fix to your example here:
function stateRules( next, prev ){ // first argument is new state, second - the previous one.
if( next.second_checkbox_key.enabled && !prev.second_checkbox_key.enabled ){
next.first_checkbox_key = { enabled : false };
}
if( next.first_checkbox_key.enabled && !prev.first_checkbox_key.enabled ){
next.second_checkbox_key = { enabled : false };
}
return next;
}
And
const componentLink = Link.state(this, 'container').pipe( stateRules );
Yes, also:
getInitialState: function () {
return {
container: {
second_checkbox_key: {
'enabled': false // Your initial state should be valid according to your rules.
},
first_checkbox_key: {
'enabled': true
}
}
}
},
It works as you want. :)
So I have been debugging this for my coworker and I think I discovered a bug with Input.
The situation is that we have two checkboxes. If the first checkbox is ticked, it should set the second checkbox to unticked.
Functional code:
tags.jsx/Input and CheckedLink doesn't work Replacing the first checkbox with a checkedLink using Input from
tags.jsx
and an onChange doesn't work.Adding an onChange function the normal way also doesn't work