Search code examples
validationbackbone.jsbackbone-viewsbackbone-stickit

Backbone-validation.js on Subview


I've been following an online example of backbone validation online:

http://jsfiddle.net/thedersen/c3kK2/

So far so good, but now I'm getting into validating subviews and they're not working.

My code looks like this:

var ScheduleModel = Backbone.Model.extend({
    validation: {
        StartDate: {
            required: true,
            fn: "isDate"
        },
        StartTime: [{
            required: true
        },
        {
            pattern: /^([0-2]\d):([0-5]\d)$/,
            msg: "Please provide a valid time in 24 hour format. ex: 23:45, 02:45"
        }],
        EndDate: {
            required: true,
            fn: "isDate"
        }
    },
    isDate: function (value, attr, computed) {
        if (isNaN(Date.parse(value))) {
            return "Is not a valid Date";
        }
    }
});
var ScheduleView = Backbone.View.extend({
    tagName: "div",
    template: _.template($("#scheduleAddTemplate").html()),
    render: function () {

        // append the template to the element
        this.$el.append(this.template(this.model.toJSON()));
        // set the schedule type
        var renderedInterval = SetScheduleType(this.model.attributes.ScheduleType.toLowerCase());
        // append to the interval
        $("#Interval", this.$el).append(renderedInterval.el);
        this.stickit();
        return this;
    },
    events: {

        "submit #NewScheduleForm": function (e) {
            e.preventDefault();
            if (this.model.isValid(true)) {
                this.model.save(null,
                {
                    success: function (schedule) {

                      //do stuff

                    }
                },
                { wait: true });
            }
        }
    },
    bindings: {
        "[name=ScheduleType]": {
            observe: "ScheduleType",
            setOptions: {
                validate: true
            }
        },
        "[name=StartDate]": {
            observe: "StartDate",
            setOptions: {
                validate: true
            }
        },
        "[name=StartTime]": {
            observe: "StartTime",
            setOptions: {
                validate: true
            }
        },
        "[name=EndDate]": {
            observe: "EndDate",
            setOptions: {
                validate: true
            }
        }
    },
    initialize: function () {
        Backbone.Validation.bind(this);
    },
    remove: function () {
        Backbone.Validation.unbind(this);
    }

});

The possible interval I'm currently working with is the following:

var MonthModel = Backbone.Model.extend({
    defaults: {
        DayOfMonth: 1,
        MonthsToSkip: 1
    },
    MonthsToSkip: {
        required: true,
        min: 1,
        msg: "Number must be greater than 1"
    },
    DayOfMonth: {
        required: function (val, attr, computed) {
            console.log(computed.ScheduleType);
            if (computed.ScheduleType === "monthly") {
                return true;
            }
            return false;
        }
    }
});
var MonthlyView = Backbone.View.extend({
    tagName: "div",
    attributes: function () {
        return { id: "Monthly", class: "inline co-xs-4" };
    },
    template: _.template($("#monthEditTemplate").html()),

    render: function () {
        // append the template to the element
        this.$el.append(this.template(this.model.toJSON()));
        this.stickit();
        return this;
    },
    bindings: {
        "[name=DayOfMonth]": {
            observe: "DayOfMonth",
            setOptions: {
                validate: true
            }
        },
        "[name=MonthsToSkip]": {
            observe: "MonthsToSkip",
            setOptions: {
                validate: true
            }
        }
    },
    initialize: function () {
        Backbone.Validation.bind(this);
    },
    remove: function () {
        Backbone.Validation.unbind(this);
    }
});

Does anyone have any idea why the subview isn't validating?


Solution

  • Found the way to do it. Posting how it's done in case anyone else ever finds this a problem. I'm only going to show the relevant bits of code without all the bindings, initializing ect.

    var ScheduleView = Backbone.View.extend({
        render: function () {
    
            // this.Interval
            this.Interval = SetScheduleType(this.model.attributes.ScheduleType.toLowerCase(), this.model);
            // set the changed interval view
            $("#Interval", this.$el).append(this.Interval.render().el);
    
            this.stickit();
            return this;
        },
    
        events: {
            "change #NewScheduleForm": function (e) {
                // validate the subview when changes are made
                this.Interval.model.validate();
            },
            "change #ScheduleType": function (e) {
                e.preventDefault();
                var model = this.model;
                var newSchedType = e.target.value;
                this.model.attributes.ScheduleType = e.target.value;
                this.Interval = SetScheduleType(newSchedType, model);
                $("#Interval").html(this.Interval.render().el);
            },
            "submit #NewScheduleForm": function (e) {
                e.preventDefault();
                if ((this.model.isValid(true)) && (this.Interval.model.isValid(true))) {
                    console.log("Success");
                    this.model.save(null,
                    {
                        success: function (schedule) {
                             //do stuff
                        }
                    },
                    { wait: true });
                }
            }
        }
        });
    

    Essentially I turned the subview into an attribute on the master view. I manually call the validation for the subview on any changes to the master view and on submitting the form.