I found a very peculiar behavior that I cannot explain. I'm using RxJS to update a set of checkboxes based on a BehaviorSubject's value. I don't want to change the checked attribute in the event handler nor let the browser handle it, so I use preventDefault
and call next
to set the new value. Then, in my subscribe
callback I attempt to set the input's checked
attribute, but it seemingly has no effect.
Run the snippet below, and try changing any of the checkboxes. Notice that each time the element's name and supposed checked
value is logged, which would seem to indicate that everything's in order, except the inputs themselves do not change states. I added additional styling to make checked items more visible.
const { BehaviorSubject } = rxjs;
const { distinctUntilChanged } = rxjs.operators;
const $checkboxes = Array.from(document.querySelectorAll('input[type="checkbox"]'));
const settings = {
a: false,
b: true,
c: false,
d: false,
e: true,
f: true,
}
const sources = {};
const observers = {};
$checkboxes.forEach(el => {
const { name } = el;
el.checked = settings[name];
sources[name] = new BehaviorSubject(el.checked);
observers[name] = sources[name].asObservable().pipe(distinctUntilChanged());
el.addEventListener('click', e => {
e.preventDefault();
const { name } = e.target;
sources[name].next(!settings[name]);
});
observers[name].subscribe(value => {
settings[name] = value;
el.checked = settings[name];
console.log(name, el.name, el.checked, value);
});
})
console.clear();
label {
display: inline-block;
margin: 3px;
}
input:checked + span {
font-weight: bold;
text-decoration: underline;
}
<label><input type="checkbox" name="a"> <span>Option A</span></label>
<label><input type="checkbox" name="b"> <span>Option B</span></label>
<label><input type="checkbox" name="c"> <span>Option C</span></label>
<label><input type="checkbox" name="d"> <span>Option D</span></label>
<label><input type="checkbox" name="e"> <span>Option E</span></label>
<label><input type="checkbox" name="f"> <span>Option F</span></label>
<script src="https://unpkg.com/rxjs@6.2.2/bundles/rxjs.umd.min.js"></script>
Of course, this is just an MCVE, my actual code is split between multiple files and classes. I was thinking that maybe it has something to do with the way the variables are passed around, but notice that el.name
and name
are identical in the logged values, meaning that el
should be the same element as before.
Wrapping the assignment to el.checked
in a setTimeout
appears to solve the issue, but doing that is almost never the right solution. I'd like to know what's causing this behavior and how I could make this kind of setup work without hacks.
Aucun commentaire:
Enregistrer un commentaire