Skip to content
Snippets Groups Projects
Commit 4f319002 authored by Patriarche Rémi's avatar Patriarche Rémi Committed by P. FONTANET
Browse files

fix: toggle ne fonctionne pas avec ngModel

parent abfb9663
No related branches found
No related tags found
No related merge requests found
......@@ -27,6 +27,10 @@
- break `radio` suppression des inputs `bindLabel` `bindValue` `bindAideRadio` au profit d'un modèle (cf. guide de migration)
- break: `tag`, la propriété `href` est remplacé par `link` ou `routerLink`
- break: `tag`, suppression de la propriété `disabled`
- break: `toogle` l'input `defaultChecked` a été supprimé
- break: `toogle` l'input `showCheckedLabel` a été renommé `showCheckedHint`
- break: `toogle` l'input `dataLabelChecked` a été renommé `checkedHintLabel`
- break: `toogle` l'input `dataLabelUnchecked` a été renommé `uncheckedHintLabel`
## 1.0.0-rc.4
......
......@@ -62,6 +62,10 @@ Ce guide trace les changements non rétrocompatibles introduits au cours de la p
### Toggle
- `name` est remplacé par `ìd`
- l'input `defaultChecked` a été supprimé car il n'était pas compatible avec le script DSFR
- l'input `showCheckedLabel` a été renommé `showCheckedHint`
- l'input `dataLabelChecked` a été renommé `checkedHintLabel`
- l'input `dataLabelUnchecked` a été renommé `uncheckedHintLabel`
### Radios / Radios extended
......
import { AfterContentInit, Input } from '@angular/core';
import { AfterContentInit, Component, Input } from '@angular/core';
import { v4 as uuidv4 } from 'uuid';
import { AbstractControlAccessorComponent } from './abstract-control-accessor.component';
/**
* Ce composant est le contrôle abstrait des contrôles Dsfr possédant un id et un label. */
@Component({ template: '' })
export abstract class AbstractControlComponent<T>
extends AbstractControlAccessorComponent<T>
implements AfterContentInit
......
......@@ -4,15 +4,13 @@
[ngClass]="{ 'fr-toggle--label-left': labelPosition === 'left', 'fr-toggle--border-bottom': showSeparator }">
<input
type="checkbox"
class="fr-toggle__input"
[attr.id]="id"
[attr.name]="id"
class="fr-toggle__input"
[attr.aria-describedby]="hintId"
[attr.disabled]="disabled ? 'true' : null"
[attr.checked]="defaultChecked ? 'true' : null"
[checked]="value"
[value]="value"
(change)="onValueChange($event)" />
[attr.disabled]="disabled ? true : null"
[attr.checked]="value ? true : null"
[(ngModel)]="value" />
<label
class="fr-toggle__label"
[attr.for]="id"
......
import { AfterContentInit, Component, forwardRef, Input, ViewEncapsulation } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { v4 as uuidv4 } from 'uuid';
import { Component, forwardRef, Input, ViewEncapsulation } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { DsfrPosition, DsfrPositionConst } from '../../commons';
import { I18nService } from '../../commons/i18n/i18n.service';
import { AbstractControlComponent } from '../forms/abstract-control.component';
@Component({
selector: DsfrToggleComponent.SELECTOR,
......@@ -16,22 +16,12 @@ import { I18nService } from '../../commons/i18n/i18n.service';
},
],
})
export class DsfrToggleComponent implements ControlValueAccessor, AfterContentInit {
export class DsfrToggleComponent extends AbstractControlComponent<boolean> {
static readonly SELECTOR = 'ngx-dsfr-toggle';
/** Utilisé pour lier le champ à son label, généré automatiquement apr défaut */
@Input() id = '';
/** Libellé du toggle. */
@Input() label: string;
/** Texte permettant de clarifier l'action. */
@Input() hint: string;
/** Valeur d'initialisation de l'attribut checked de l'input. */
// FIXME Pour moi devrait supprimé et remplacé par value
@Input() defaultChecked = false;
/** Position du libellé, à droite par défaut. */
@Input() labelPosition: DsfrPosition = DsfrPositionConst.RIGHT;
......@@ -39,18 +29,19 @@ export class DsfrToggleComponent implements ControlValueAccessor, AfterContentIn
* Petit libellé décrivant l'état de l’interrupteur (activé / désactivé), placé en dessous du bouton”.
* Il est conseillé de le mettre afin de faciliter la compréhension de l’utilisateur - optionnel.
*/
@Input() showCheckedLabel = true;
@Input() showCheckedHint = true;
/** Libellé à afficher lorsque le toggle est activé. */
// FIXME Non utilisé
@Input() dataLabelChecked = '';
/** Libellé à afficher lorsque le toggle est désactivé. */
// FIXME Non utilisé
@Input() dataLabelUnchecked = '';
/**
* Propriété permettant de surcharger le petit libellé court dénotant l'état checked du toggle, sans avoir à passer
* par un fichier d'internationalisation.
*/
@Input() checkedHintLabel: string;
/** Permet de désactiver le toggle. */
@Input() disabled = false;
/**
* Propriété permettant de surcharger le petit libellé court dénotant l'état checked du toggle, sans avoir à passer
* par un fichier d'internationalisation.
*/
@Input() uncheckedHintLabel: string;
/**
* Affiche un séparateur horizontal sous le composant.
......@@ -58,50 +49,19 @@ export class DsfrToggleComponent implements ControlValueAccessor, AfterContentIn
*/
@Input() showSeparator: boolean;
/** Modèle interne du toggle. */
value: boolean;
constructor(private i18n: I18nService) {}
constructor(private i18n: I18nService) {
super();
}
get hintId() {
return this.id + '-hint-text';
}
ngAfterContentInit() {
if (!this.id) this.id = uuidv4();
}
onTouched = (_: any) => {};
onChange = (_: any) => {};
writeValue(value: any): void {
this.value = value;
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
onValueChange($event: any) {
// dispatch model change on parent context
this.value = $event?.target?.checked;
this.onChange(this.value);
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
getDataLabelChecked(): string {
return this.showCheckedLabel ? this.i18n.t('toggle.dataLabelChecked') : '';
return this.showCheckedHint ? this.checkedHintLabel || this.i18n.t('toggle.dataLabelChecked') : '';
}
getDataLabelUnchecked(): string {
return this.showCheckedLabel ? this.i18n.t('toggle.dataLabelUnchecked') : '';
return this.showCheckedHint ? this.uncheckedHintLabel || this.i18n.t('toggle.dataLabelUnchecked') : '';
}
}
import { FormsModule } from '@angular/forms';
import { componentWrapperDecorator, moduleMetadata } from '@storybook/angular';
import { moduleMetadata } from '@storybook/angular';
import { Meta, Story } from '@storybook/angular/types-6-0';
import { DsfrPositionConst } from '../../commons';
import { DsfrToggleComponent } from './toggle.component';
......@@ -40,26 +40,45 @@ Default.args = {
hint: `Texte d'aide pour clarifier l'action`,
labelPosition: DsfrPositionConst.RIGHT,
showSeparator: false,
defaultChecked: false,
};
/** WithNgModel */
export const WithNgModel = Template.bind({});
WithNgModel.storyName = 'With NgModel';
WithNgModel.args = {
/** Init with True */
export const InitWithTrue = Template.bind({});
InitWithTrue.args = {
label: 'Label action interrupteur',
hint: `Texte d'aide pour clarifier l'action`,
defaultChecked: true,
labelPosition: DsfrPositionConst.RIGHT,
showSeparator: false,
value: true,
};
WithNgModel.decorators = [
componentWrapperDecorator(
(story) => `
<div style="font-weight:bold;color:red;padding:10px;border:1px solid red">
Ne fonctionne pas sans doute à cause de <a href='https://github.com/storybookjs/storybook/issues/14643'>cette régression</a>
</div>
${story}
<br>
<span>model: {{ yourModel }}</span>
const myModel = { enabled: true };
/** WithNgModel */
export const WithNgModel: Story<DsfrToggleComponent> = (args) => ({
props: { ...args, myModel },
template: `
<ngx-dsfr-toggle [(ngModel)]="myModel.enabled">
<span label>Est sensé être piloté par <code>myModel.enabled</code></span>
</ngx-dsfr-toggle>
<span>myModel.enabled: {{ myModel.enabled }}</span>
<div style="font-weight:bold;padding:10px;margin-top:25px;border:1px dotted red">
Ne fonctionne pas sous SB sans doute à cause de
<a href='https://github.com/storybookjs/storybook/issues/14643'>cette régression</a>.
&nbsp;A retester ultérieurement avec SB 7.x
</div>
`,
),
];
});
WithNgModel.storyName = 'With NgModel';
// WithNgModel.decorators = [
// componentWrapperDecorator(
// (story) => `
//
// ${story}
// <br>
// <span>model: {{ yourModel }}</span>
// `,
// ),
// ];
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment