J'ai un petit problème en essayant de créer une case à cocher qui sélectionne et désélectionne d'autres cases à cocher individuelles (tout sélectionner/désélectionner) avec Réagir . J'ai lu http://facebook.github.io/react/docs/forms.html et découvert qu'il existe des différences entre contrôlé et non contrôlé <input>
s. Mon code de test est le suivant:
var Test = React.createClass({
getInitialState: function() {
return {
data: [
{ id: 1, selected: false },
{ id: 2, selected: false },
{ id: 3, selected: false },
{ id: 4, selected: false }
]
};
},
render: function() {
var checks = this.state.data.map(function(d) {
return (
<div>
<input type="checkbox" data-id={d.id} checked={d.selected} onChange={this.__changeSelection} />
{d.id}
<br />
</div>
);
});
return (
<form>
<input type="checkbox" ref="globalSelector" onChange={this.__changeAllChecks} />Global selector
<br />
{checks}
</form>
);
},
__changeSelection: function(e) {
var id = e.target.getAttribute('data-id');
var state = this.state.data.map(function(d) {
return {
id: d.id,
selected: (d.id === id ? !d.selected : d.selected)
};
});
this.setState({ data: state });
},
__changeAllChecks: function(e) {
var value = this.refs.globalSelector.getDOMNode().checked;
var state = this.state.data.map(function(d) {
return { id: d.id, selected: value };
});
this.setState({ data: state });
}
});
React.renderComponent(<Test />, document.getElementById('content'));
Le "sélecteur global" fonctionne comme prévu: lorsqu'il est sélectionné, tous les autres contrôles sont sélectionnés. Le problème est que le gestionnaire __changeSelection()
n'est pas déclenché lorsque l'une des autres cases à cocher est activée.
Je ne sais pas quelle est la bonne façon de faire fonctionner cela. Peut-être que le modèle React n'est pas le meilleur pour modéliser ce type d'interaction? Que puis-je faire?
Merci d'avance
Dans votre fonction render
, la portée de this
pour la fonction de mappage checks
est différente de render
, qui est la portée dont vous avez besoin pour __changeSelection
, donc this.__changeSelection
ne localisera pas une propriété __changeSelection
. Si vous ajoutez une .bind(this)
à la fin de cette fonction de mappage, vous pouvez lier sa portée à la même this
que render
:
var checks = this.state.data.map(function(d) {
return (
<div>
<input type="checkbox" data-id={d.id} checked={d.selected} onChange={this.__changeSelection} />
{d.id}
<br />
</div>
);
}.bind(this));
Sur une note latérale, je passerais simplement le id
à la fonction de gestionnaire au lieu d'attribuer des attributs de données. Cela supprimera la nécessité de localiser cet élément dans votre gestionnaire:
var checks = this.state.data.map(function(d) {
return (
<div>
<input type="checkbox" checked={d.selected} onChange={this.__changeSelection.bind(this, d.id)} />
{d.id}
<br />
</div>
);
}.bind(this));
Mettez ensuite à jour votre fonction __changeSelection
Pour passer le id
comme premier argument et supprimez la ligne de recherche d'attribut:
__changeSelection: function(id) {
var state = this.state.data.map(function(d) {
return {
id: d.id,
selected: (d.id === id ? !d.selected : d.selected)
};
});
this.setState({ data: state });
}
Voici un exemple de tout cela mis en place, avec un jsfiddle pour que vous puissiez l'essayer :
/** @jsx React.DOM */
var Test = React.createClass({
getInitialState: function() {
return {
data: [
{ id: 1, selected: false },
{ id: 2, selected: false },
{ id: 3, selected: false },
{ id: 4, selected: false }
]
};
},
render: function() {
var checks = this.state.data.map(function(d) {
return (
<div>
<input type="checkbox" checked={d.selected} onChange={this.__changeSelection.bind(this, d.id)} />
{d.id}
<br />
</div>
);
}.bind(this));
return (
<form>
<input type="checkbox" ref="globalSelector" onChange={this.__changeAllChecks} />Global selector
<br />
{checks}
</form>
);
},
__changeSelection: function(id) {
var state = this.state.data.map(function(d) {
return {
id: d.id,
selected: (d.id === id ? !d.selected : d.selected)
};
});
this.setState({ data: state });
},
__changeAllChecks: function() {
var value = this.refs.globalSelector.getDOMNode().checked;
var state = this.state.data.map(function(d) {
return { id: d.id, selected: value };
});
this.setState({ data: state });
}
});
React.renderComponent(<Test />, document.getElementById('content'));
Si vous avez affaire à des cases à cocher, vous pouvez utiliser l'attribut checkedLink
. Voici une autre implémentation possible, qui rend la case à cocher globale contrôlée (au lieu d'être incontrôlée dans les réponses actuelles):
var Test = React.createClass({
getInitialState: function() {
return {
globalCheckbox: false,
data: [
{ id: 1, selected: false },
{ id: 2, selected: false },
{ id: 3, selected: false },
{ id: 4, selected: false }
]
};
},
changeCheckForId: function(id,bool) {
this.setState(
{
data: this.state.data.map(function(d) {
var newSelected = (d.id === id ? bool : d.selected);
return {id: d.id, selected: newSelected};
}
)});
},
changeCheckForAll: function(bool) {
this.setState({
globalCheckbox: true,
data: this.state.data.map(function(d) {
return {id: d.id, selected: bool};
})
});
},
linkCheckbox: function(d) {
return {
value: d.selected,
requestChange: function(bool) { this.changeCheckForId(d.id,bool); }.bind(this)
};
},
linkGlobalCheckbox: function() {
return {
value: this.state.globalCheckbox,
requestChange: function(bool) { this.changeCheckForAll(bool); }.bind(this)
};
},
render: function() {
var checks = this.state.data.map(function(d) {
return (
<div>
<input key={d.id} type="checkbox" checkedLink={this.linkCheckbox(d)} />
{d.id}
<br />
</div>
);
}.bind(this));
return (
<form>
<input type="checkbox" checkedLink={this.linkGlobalCheckbox()} />Global selector
<br />
{checks}
</form>
);
},
});
Il est plus simple d'utiliser checkedLink=this.linkState("checkboxValue")
avec LinkedStateMixin
si l'état à muter n'est pas profondément imbriqué (comme c'est le cas dans cette question)
Modifier : checkedLink
et valueLink
sont déconseillés mais ont été recommandés dans les versions précédentes de React.