1

I have an observable array and it is working fine. i have add button for adding element to this array after adding/push element to this array the added element is not observable but still others are observable. I am using mobx-react. this is the code snippet:

    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 is an observable array.

please suggest some ideas.

1 Answer 1

0

You cannot concat an observable array. Try to push the new element instead:

this.model.metaValues.push(newValue);
1
  • @NishilAthikkal It should work. Include the code for your entire react component. There might be something else that is wrong.
    – Tholle
    Commented Jan 16, 2017 at 11:21

Not the answer you're looking for? Browse other questions tagged or ask your own question.