Backbone.undo.js没有跟踪我的第二个跨度并且没有保存起始值

时间:2014-09-25 09:50:10

标签: javascript jquery html backbone.js

我有一个小应用,我想点击它们来编辑 spans 。我有两个跨度但是当我编辑第二个跨度时,第一个跨度会自动更改为与第二个跨度相同的值。我也无法更改为第一个跨度值,因为单击撤消的第一个值是 foo

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Backbone.Undo sample</title>
    <style>
        body {
            font-family: sans-serif;
            line-height: 140%;
        }

        #centered {
            position: absolute;
            top: 50%;
            left: 50%;
            margin-left: -180px;
            margin-top: -120px;
        }
    </style>
</head>
<body>
    <ol id="centered">
        <li>
            <span type="text" id="input" value="foo">span1 </span>
            <button id="set">set</button>
        </li>
        <li>
            <span type="text" id="input2" value="foo">span2 </span>
            <button id="Button1">set</button>
        </li>
        <li>
            <button id="undo">undo</button>
            <button id="redo">redo</button>
        </li>
    </ol>
    <script src="jquery-1.9.1.js"></script>
    <script src="underscore.js"></script>
    <script src="backbone.js"></script>
    <script src="../Backbone.Undo.js"></script>
    <script>
        $(function () {
            var model = new Backbone.Model({ "text": "foo" }),
            View = Backbone.View.extend({
                initialize: function () {
                    // If the model's text changes, update the view
                    this.model.on("change:text", function (model, text, options) {
                        if (text != this.$el.text()) {
                            this.$el.text(text);
                        }
                    }, this);
                }
            })
            view = new View({
                model: model,
                el: $("#input")
            })
            // Now: The undo/redo part 
            var undoManager = new Backbone.UndoManager;
            undoManager.register(model);
            undoManager.startTracking();

            $("#undo").on("click", function () {
                undoManager.undo();
            })
            $("#redo").on("click", function () {
                undoManager.redo();
            })
            $("#input").on("click", function () {
                var element = document.getElementById("input");
                element.innerHTML = prompt("#input", element.innerHTML);
                model.set("text", $("#input").text());
            })
            $("#input2").on("click", function () {
                var element = document.getElementById("input2");
                element.innerHTML = prompt("#input2", element.innerHTML);
                model.set("text", $("#input2").text());
            })
        })
    </script>
</body>
</html>

1 个答案:

答案 0 :(得分:2)

从我可以看到你使用1个模型和1个视图,但你希望它们独立行动。因此,当您单击span2时,您仍然设置相同的模型,这就是它们都改变的原因。

对于这个我会使用单独的模型和两个跨度的单独视图,如此

var model = new Backbone.Model({
    "text": "span1"
});
var model2 = new Backbone.Model({
    "text": "span2"
});
var View = Backbone.View.extend({
    initialize: function () {
        // If the model's text changes, update the view
        this.model.on("change:text", function (model, text, options) {
            if (text != this.$el.text()) {
                this.$el.text(text);
            }
        }, this);
    }
});
var view1 = new View({
    model: model,
    el: $("#input")
});

var view2 = new View({
    model: model2,
    el: $("#input2")
});

然后在撤消寄存器中注册您的其他模型

// Now: The undo/redo part 
var undoManager = new Backbone.UndoManager;
undoManager.register(model);
undoManager.register(model2);
undoManager.startTracking();

最后更改span2上的点击处理程序以编辑新模型

$("#input2").on("click", function () {
    var element = document.getElementById("input2");
    element.innerHTML = prompt("#input2", element.innerHTML);
    model2.set("text", $("#input2").text());
})

here is a fiddle with it all together

您还可以通过让视图处理事件而不是在外部执行此操作来充分利用主干。这是一个例子

var View = Backbone.View.extend({
    initialize: function () {
        // If the model's text changes, update the view
        this.model.on("change:text", function (model, text, options) {
            if (text != this.$el.text()) {
                this.$el.text(text);
            }
        }, this);
    },

    events: {
        'click': 'editValue'
    },
    editValue: function () {
        var data = prompt("#input2", this.model.get("text"));
        if(data)
        {
            this.model.set("text", data);
        }
    }
    });

现在视图处理模型的这一变化,我们也不必从html中获取数据,我们始终将其保存在模型中。这是一个更新的小提琴,显示了这种技术http://fiddle.jshell.net/leighking2/2vx00s4b/9/


更多Backboney方法,为每个模型使用模板,用于保存模型的集合,然后是用于显示集合的视图和用于显示每个模型的视图。我试图添加注释以显示不同部分正在做什么,询问是否要清除任何内容

Fiddle of this example

<强> HTML

<script type="text/template" id="model-template">
    <span type="text" class="input" value="foo"><%= text %></span>
        <button class="remove">remove</button>
</script>
<div id="centered">
    <ol id="collection-hook"> 
    </ol>
    <button id="undo">undo</button>
    <button id="redo">redo</button>
    <button id="add">add</button>
</div>

<强> JS

var Model = Backbone.Model.extend({
    defaults: {
        text: "Click To Edit Text"
    }
});
var Collection = Backbone.Collection.extend({
    model: Model
});

var ModelView = Backbone.View.extend({
    tagName: "li",
    className: "model",

    //get the template and cache it for future use
    template:_.template($('#model-template').html()),
    initialize: function() {
        // If the model's text changes, update the view
        this.listenTo(this.model, "change:text", this.render, this);
        //if the model is removed from the collection close this view
        this.listenTo(this.model, 'remove', this.close, this);
    },

    //events this view will be listening for
    events: {
        'click span.input': 'editValue',
        'click button.remove': 'removeModel',
    },

    //get the models collection from it's self and tell the collection to remove the model
    removeModel: function() {
        this.model.collection.remove(this.model);
    },

    //ensure model and all events are destroyed and remove this view from the DOM
    close: function() {
        this.model.destroy();
        this.remove();
        this.unbind();
        this.stopListening();
    },

    //render this view with the models data
    render: function() {

        //attach the generated template to this views $el
        this.$el.html(this.template({
            text: this.model.get("text")
        }));

        //return this view so collection view can decided where to place it on the DOM
        return this;
    },

    editValue: function() {
        var data = prompt("Change text", this.model.get("text"));
        if (data) {
            this.model.set("text", data);
        }
    }
});

var CollectionView = Backbone.View.extend({
    el: $("#centered"),
    //store a refrence to where you would like to add your models
    collectinoHook: $("#collection-hook", this.$el),

    initialize: function() {
        this.undoManager = new Backbone.UndoManager;

        this.undoManager.startTracking();

        //when ever a new model is added to the collection call the function
        //to render it
        this.listenTo(this.collection, 'add', this.renderOne, this);

    },

    events: {
        'click #add': 'addModel',
        'click #redo': 'redo',
        'click #undo': 'undo',
    },

    //render the collection items one at a time
    renderOne: function(model) {
        this.undoManager.register(model);
        //create a new view using this model
        var view = new ModelView({
            model: model
        });

        //append the new view to you list
        this.collectinoHook.append(view.render().el);
    },

    //use this to render the view with existing models in the collection
    render: function() {
        //clear the current views that have been rendered not the cleanest method as
        //those views will still exist but this is a quick example
        this.collectinoHook.html('');
        this.collection.each(_.bind(function(model) {
            this.renderOne(model);
        },this));
    },


    undo: function() {
        this.undoManager.undo();
    },
    redo: function() {
        this.undoManager.redo();
    },
    addModel: function() {

        //create a new model and add it to the collection
        var model = new Model();
        this.collection.add(model);
    },

});

var collection = new Collection();
var collectionView = new CollectionView({
    collection: collection
});