1

監視可能な配列があり、正常に動作しています。この配列に要素を追加/プッシュした後、この配列に要素を追加するためのボタンを追加しました追加された要素は観察できませんが、それでも他の要素は観察可能です。私はmobx-reactを使用しています。これはコード スニペットです。

    import * as React from "react";
import {computed, observable} from "mobx";
import {observer} from "mobx-react";
import {AreaBody} from "../General/AreaBody";
import {AppStore} from "../Stores/AppStore";
import {Strings} from "../Stores/StringsStore";
import {DialogStore, DialogResult} from "../Stores/DialogStore";
import {NotificationStore} from "../Stores/NotificationStore";
import {AddButton} from "../Buttons/AddButton";
import {SaveButton} from "../Buttons/SaveButton";
import {DeleteButton} from "../Buttons/DeleteButton";
import {CloseButton} from "../Buttons/CloseButton";
import {Toolbar} from "../General/Toolbar";
import {InputBooleanComponent} from "../Inputs/InputBooleanComponent";
import {InputNumberComponent} from "../Inputs/InputNumberComponent";
import {InputChoiseComponent} from "../Inputs/InputChoiseComponent";
import {InputTextComponent} from "../Inputs/InputTextComponent";
import * as MetaManagement from "../MetaManagement";
import * as Utilities from "../Utilities";
import {Urls} from "../Urls";
import * as UiStore from "../States/AreaUiInfo";

interface IMetaProps extends UiStore.IAreaUiInfo {
    params: IMetaPropsParams;
}

interface IMetaPropsParams {
    id: string;
}

@observer
export class MetaEdit extends React.Component<IMetaProps, {}> {
    @observable model = new MetaManagement.MetaDetails();
    @observable hash: string;
    @observable isBusy: boolean = true;
    @observable canSaveData: boolean = false;

    componentDidMount() {
        window.addEventListener('beforeunload', this.keepOnPage);
        this.getModel();
        this.canSaveData = this.canSaveModel();
    }

    componentWillUnmount() {
        window.removeEventListener('beforeunload', this.keepOnPage);
    }


    keepOnPage = (e: any) => {
        if (this.canSaveModel()) {
            DialogStore.show("do you want to reload this site?", 'Warning!\n\nNavigating away from this page will delete your text if you haven\'t already saved it.').then((result: DialogResult) => {
                if (result == DialogResult.Yes) {
                    return 'Warning!\n\nNavigating away from this page will delete your text if you haven\'t already saved it.';
                }
            });
        }
    }

    componentDidUpdate(prevProps: IMetaProps) {
        if (this.props.params.id != this.model.guid) {
            this.getModel();
            this.canSaveData = this.canSaveModel();
        }
    }

    getModel() {
        this.isBusy = true;
        MetaManagement.getMetaAsync(this.props.params.id).then(model => {
            this.model = this.fillMissing(model);
            this.hash = JSON.stringify(this.model);
            this.forceUpdate();
            NotificationStore.clearMessage();
            this.isBusy = false;
        }).catch(error => {
            NotificationStore.showErrorMessage(error);
        });
    }

    //@computed get canSave(): boolean {
    //  for (let i = 0; i < this.model.metaValues.length; i++) {
    //      if (!this.model.metaValues[i].value.isValid || !this.model.metaValues[i].value.value) {
    //          return false;
    //      }
    //  }
    //  return this.model.id.isValid && this.model.caption.isValid && (this.hash != JSON.stringify(this.model));
    //}

    canSaveModel = () => {
        for (let i = 0; i < this.model.metaValues.length; i++) {
            if (!this.model.metaValues[i].value.isValid || !this.model.metaValues[i].value.value) {
                return false;
            }
        }
        return this.model.id.isValid && this.model.caption.isValid && (this.hash != JSON.stringify(this.model));
    }

    handleSave = () => {
        if (this.canSaveModel()) {
            let updateModel = new MetaManagement.MetaDetailsUpdate();
            updateModel.lastModified = this.model.lastModified;
            updateModel.captionLastModified = this.model.captionLastModified;
            updateModel.guid = this.model.guid;
            updateModel.dataType = this.model.dataType.value;
            updateModel.id = this.model.id.value;
            updateModel.caption = this.model.caption.value;
            updateModel.required = this.model.required.value;
            updateModel.showAsColumn = this.model.showAsColumn.value;
            updateModel.showAsFilter = this.model.showAsFilter.value;
            updateModel.filterMaxValues = this.model.filterMaxValues.value;
            updateModel.regex = this.model.regex.value;
            updateModel.multiple = this.model.multiple.value;
            updateModel.languageDependent = this.model.languageDependent.value;
            updateModel.predefined = this.model.predefined.value;
            if (updateModel.predefined) {
                updateModel.metaValues = this.model.metaValues;
            }
            else {
                updateModel.metaValues = [];
            }

            MetaManagement.insertOrUpdateMetaAsync(updateModel).then(model => {
                this.model = this.fillMissing(model);
                if (this.model.isValid) {
                    this.hash = JSON.stringify(this.model);
                    NotificationStore.showSuccessMessage(Strings.general.saveSuccessMessage);
                }
                else {
                    NotificationStore.showErrorMessage(model.validationMessage);
                }
            }).catch(error => {
                NotificationStore.showErrorMessage(error);
            });
        }
        this.canSaveData = this.canSaveModel();
    }

    handleDelete = () => {
        DialogStore.show(Utilities.format(Strings.general.dialogDeleteTitle, this.model.caption.value), Utilities.format(Strings.general.dialogDeleteText, this.model.caption.value)).then(result => {
            if (result == DialogResult.Yes) {
                MetaManagement.removeMetaAsync({ guid: this.model.guid, lastModified: null }).then(status => {
                    NotificationStore.showSuccessMessage(Strings.general.deleteSuccessMessage);
                    AppStore.history.replace(Urls.metas);
                }).catch(error => {
                    NotificationStore.showErrorMessage(error);
                });
            }
        });
    }

    handleCancel = () => {
        AppStore.history.replace(Urls.metas);
    }

    handleChange = () => {
        this.canSaveData = this.canSaveModel();
        NotificationStore.clearMessage();
    }

    @computed get showRegex(): boolean {
        return this.model.dataType.value == "Text" || this.model.dataType.value == "Hierarchy";
    }

    @computed get showLanguageDependent(): boolean {
        return this.model.dataType.value == "Text" || this.model.dataType.value == "Hierarchy";
    }

    @computed get showMultiple(): boolean {
        return this.model.dataType.value != "Boolean";
    }

    @computed get showPredifined(): boolean {
        return this.model.dataType.value == "Text" || this.model.dataType.value == "Number" || this.model.dataType.value == "Hierarchy" || this.model.dataType.value == "DocumentLink";
    }

    fillMissing(model: MetaManagement.MetaDetails) {
        model.dataType.label = Strings.metaManagement.metaEdit.dataType;
        model.id.label = Strings.metaManagement.metaEdit.id;
        model.id.placeHolder = Strings.metaManagement.metaEdit.idPlaceHolder;
        model.caption.label = Strings.metaManagement.metaEdit.caption;
        model.caption.placeHolder = Strings.metaManagement.metaEdit.captionPlaceHolder;
        model.regex.label = Strings.metaManagement.metaEdit.regex;
        model.regex.placeHolder = Strings.metaManagement.metaEdit.regexPlaceHolder;
        model.predefined.label = Strings.metaManagement.metaEdit.preDefined;
        model.multiple.label = Strings.metaManagement.metaEdit.multiple;
        model.required.label = Strings.metaManagement.metaEdit.required;
        model.languageDependent.label = Strings.metaManagement.metaEdit.languageDependent;
        model.showAsColumn.label = Strings.metaManagement.metaEdit.showAsColumn;
        model.showAsFilter.label = Strings.metaManagement.metaEdit.showAsFilter;
        model.filterMaxValues.label = Strings.metaManagement.metaEdit.filterMaxValues;
        model.filterMaxValues.placeHolder = Strings.metaManagement.metaEdit.filterMaxValuesPlaceHolder;
        for (let i = 0; i < model.metaValues.length; i++) {
            model.metaValues[i].value.regex = "^[a-zA-Z0-9- _]+$";
        }
        return model;
    }

    render() {
        let regex = this.showRegex ? <InputTextComponent model={this.model.regex} onChange={this.handleChange} /> : null;
        let languageDependent = this.showLanguageDependent ? <InputBooleanComponent model={this.model.languageDependent} onChange={this.handleChange} /> : null;
        let multiple = this.showMultiple ? <InputBooleanComponent model={this.model.multiple} onChange={this.handleChange} /> : null;
        let predefined = this.showPredifined ? <InputBooleanComponent model={this.model.predefined} onChange={this.handleChange} /> : null;
        let values = this.showPredifined && this.model.predefined.value ? <div><h2>{Strings.metaManagement.metaEdit.preDefinedValues}</h2><MetaValuesEdit handleChange={this.handleChange} values={this.model.metaValues} readonly={this.model.predefined.isReadOnly} number={this.model.dataType.value == "Number"} /></div> : null;

        return <AreaBody loading={this.isBusy} areaUiInfo={this.props.areaUiInfo}>
            <Toolbar>
                <SaveButton onClick={this.handleSave} disabled={!this.canSaveData} label={Strings.general.saveButtonLabel}/>
                <DeleteButton onClick={this.handleDelete} label={Strings.general.deleteButtonLabel}/>
                <span className="buttongroup is--buttongroup-right">
                    <CloseButton onClick={this.handleCancel} />
                </span>
            </Toolbar>
            <div className="area-grid__body-content">
                <div className="content-main">
                    <h1>{Strings.metaManagement.metaEdit.title}</h1>
                    <div>
                        <InputChoiseComponent model={this.model.dataType} onChange={this.handleChange} />
                        <InputTextComponent model={this.model.id} onChange={this.handleChange} />
                        <InputTextComponent model={this.model.caption} onChange={this.handleChange} />
                        <InputBooleanComponent model={this.model.required} onChange={this.handleChange} />
                        <InputBooleanComponent model={this.model.showAsColumn} onChange={this.handleChange} />
                        <InputBooleanComponent model={this.model.showAsFilter} onChange={this.handleChange} />
                        <InputNumberComponent model={this.model.filterMaxValues} locale={navigator.language} onChange={this.handleChange}/>
                        {regex}
                        {multiple}
                        {languageDependent}
                        {predefined}
                        {values}
                    </div>
                </div>
            </div>
        </AreaBody>;
    }
}

interface IMetaValuesProps {
    values: MetaManagement.MetaValue[];
    readonly: boolean;
    number: boolean;
    handleChange: () => void;
}

@observer
class MetaValuesEdit extends React.Component<IMetaValuesProps, {}> {


    handleAdd = () => {
        let newValue = new MetaManagement.MetaValue();
        newValue.guid = Utilities.newGuid();
        newValue.canDelete = true;
        newValue.value.isReadOnly = false;
        newValue.value.isValid = true;
        newValue.value.value = "";
        newValue.value.regex = "^[a-zA-Z0-9- _]+$";
        this.props.values.push(newValue);
        this.props.handleChange();
    }

    handleDelete = (item: MetaManagement.MetaValue) => {
        for (let i = 0; i < this.props.values.length; i++) {
            if (this.props.values[i].guid == item.guid) {
                this.props.values.splice(i, 1);
                this.props.handleChange();
                return;
            }
        }
    }

    handleChange = () => {
        this.props.handleChange();
    }

    render() {
        return <div className="list-object is--tools-single">
            <div className="toolbar">
                <span className="buttongroup is--buttongroup-right">
                    <AddButton onClick={this.handleAdd} disabled={this.props.readonly} />
                </span>
            </div>
            <ul>
                {
                    this.props.values.map(item => {
                        return <li key={item.guid}>
                            <div>
                                <div className="list-object__tools">
                                    <div className="tinytool">
                                        <DeleteButton onClick={() => this.handleDelete(item) } disabled={!item.canDelete} />
                                    </div>
                                </div>
                                <div className="list-object__name">
                                    <InputTextComponent onChange={this.handleChange} model={item.value} />
                                </div>
                            </div>
                        </li>
                    })
                }
            </ul>
        </div>;
    }
}

this.model.metaValues は監視可能な配列です。

いくつかのアイデアを提案してください。

4

1 に答える 1