1

私は最初のバックボーンアプリを作成しようとしていますが、解決できない問題が発生しました。

リンクのリストがあり、各リンクの横にカウンターがあります。リンクをクリックすると、カウンターが1ずつ増えます(これを作成しましたが、機能しています)。

次に、カウンター値が上のリンクよりも高い場合は、クリックしたリンクをリストの上位に移動します。

このような。

  • 最初のリンク(4)
  • 2番目のリンク(3)
  • 3番目のリンク(3)<-このリンクをクリックすると、2番目のリンクの上に移動します。

コンパレータとsortByを使用してみましたが、何かを試すたびに、ビューを再レンダリングできず、リンクが1つ上に移動しているように見えます。

メインビューが初期化されたとき、私は最初にリストをソートすることができました。しかし、リンクの1つをクリックした後、ビューとリストの配置を更新すると、実行方法がわかりません。

私のコード:

(function() {

window.App = {
    Models: {},
    Collections: {},
    Views: {}
};
window.template = function(id) {
    return _.template( $('#' + id).html() );
};


//Modellen
App.Models.Task = Backbone.Model.extend({
    defaults: {
        name: 'Foo Bar Baz',
        uri: 'http://www.google.com',
        counter: 0
    },

    validate: function(attr) {
            if ( ! $.trim(attr.name) ) {
                    return 'En opgave kræver en title.';
            };
    }
});

//Collection
App.Collections.Tasks = Backbone.Collection.extend({ 
    model: App.Models.Task,

    comparator: function(task) {
    return task.get('counter');
    },

});



//Singel view
App.Views.TaskView = Backbone.View.extend({
    tagName: 'li',

    template: template('Tasks'),

    initialize: function() {
        this.model.on('change', this.render, this);
        this.model.on('destroy', this.remove, this);

    },

    events: {
    'click .edit' : 'retTask',
    'click .delete' : 'destroy',
    'click .uriLink' : 'addCounter'
    },

    retTask: function() {
        var newTaskNavn = prompt('Hvad skal det nye navn være', this.model.get('name'));

        if ( !newTaskNavn ) return;
        this.model.set('name', newTaskNavn);
    },      

    destroy: function() {
        this.model.destroy();

    },

    addCounter: function(e) {
        e.preventDefault();
        var newCounter = this.model.get('counter');
        this.model.set('counter', newCounter + 1);
    },

    remove: function() {
        this.$el.remove();
    },

    render: function()  {
        this.$el.html(this.template(this.model.toJSON()) );
        return this;
    }
});

//Collection View
App.Views.TasksView = Backbone.View.extend({
    tagName: 'ul',

    initialize: function() {
        this.collection.on('add', this.addOne, this);
        this.render();
    },

    render: function() {
        this.collection.each(this.addOne, this);
        return this;
    },

    addOne: function(task) {
        var taskView = new App.Views.TaskView({ model: task });
        this.$el.append(taskView.render().el);

    }
});

App.Views.AddTask = Backbone.View.extend({
    el: '#addTask',

    initialize: function() {
    },

    events: {
        'submit' : 'submit'
    },

    submit: function(e) {
        e.preventDefault();
        var taskNavn = $(e.currentTarget).find('.navnClass').val(),
             uriNum =  $(e.currentTarget).find('.uriClass').val();

        if ( ! $.trim(taskNavn)) {

            var test =  prompt('opgaven skal have et navn', '');
            if ( ! $.trim(test)) return false;
                taskNavn = test;
        }

        if( uriNum.indexOf( "http://" ) == -1 ) {
                     addedValue = 'http://',
                     uriNum = addedValue + uriNum;
        }

        $(e.currentTarget).find('input[type=text]').val('').focus();
        //var task = new App.Models.Task({ name: taskNavn, uri: uriNum });
        this.collection.add({ name: taskNavn, uri: uriNum });
    }

});


// new tasks collection
var tasks = new App.Collections.Tasks([
{
    name: 'Foo',
    uri: 'www.google.com',
    counter: 3
},
{   
    name: 'Bar',
    uri: 'http://google.com',
    counter: 2
},
{
    name: 'Baz',
    uri: 'http://www.google.com',
    counter: 1
}
]);

 // tasks.comparator = function(task) {
 // return task.get("counter");
 // };  
 tasks.sort();

// new collection view (add)
var addTaskView = new App.Views.AddTask({ collection: tasks});

// new collection view
var tasksView = new App.Views.TasksView({ collection: tasks });
$('.tasks').html(tasksView.el);

})();

私のHTML:(誰かがシナリオを複製しようとする場合:)

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>LinkList</title>
</head>
<body>

<h1>Mine opgaver</h1>
<form action="" id="addTask">
    <input class="navnClass" type="text" placeholder="Link name"><input clas s="uriClass" type="text" placeholder="www.url-here.com">
    <button class="nyOpgave">Ny opgave</button><br />

</form>

<div class="tasks">
    <script type="text/template" id="Tasks">
        <span class="linkNavn"><%= name %></span> - <a href="<%= uri %>" class="uriLink" target="_blank"><%= uri %></a> : [<span class="counterClass"><%= counter %></span>] <button class="edit">Edit</button> <button class="delete">Delete</button>
    </script>
</div>
<script src="js/underscore.js"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script src="js/jquery.js"></script>
<script src="js/backbone.js"></script>
<script src="main.js"></script>

</body>
</html>

誰かが私がこれを理解するのを手伝ってくれますか?

/乾杯マルセル

4

2 に答える 2

3

オーケー、あなたが実行するつもりだったように、私はあなたのためにアプリケーションを作成しました.コード全体、私が書いたもの、そしてなぜ私が書いたのかを説明しようと思います.

まず、JSfiddle を見てみましょう: here

次に、説明させてください。

1.これは、リンクの名前、 href 、 id (私の例では使用されていませんが、各モデルに一意の id を割り当てることをお勧めします) と最後にリンク (モデル) へのクリック数を格納する私のモデルです。 .

var myModel = Backbone.Model.extend({
    defaults:{
        'id' : 0,
        'name' : null,
        'link' : '#',
        'clicks' : 0
    }
});

2.これは、すべてのモデルを格納するコレクションです。コレクションにモデルを追加するたびにコレクションをソートするように、コンパレータ関数を追加しました。

-:コレクションをクリック数の降順でソートする記号を追加しました(最大クリック数のリンクが最初に表示されます)

var myCollection = Backbone.Collection.extend({
        model: myModel,
        comparator: function(item) {
            return -item.get('clicks');
        }
    });

3. これが私のメイン ビューです。メイン ビューとはどういう意味ですか? このビューは、表示したいリストの主要なレンダリングを行います。ここにかなり自明なコードがあります。1 つthis.coll.bind('add change',this.render,this)、「変更」を追加しました。これは、このコレクション内のモデルのいずれかが変更されるたびに、再リスト全体をレンダリングします。これは、リンクの数を変更したときに発生し、クリックすると、リスト全体を再レンダリングします。

var myView = Backbone.View.extend({
    el: $("#someElement"),
    tagName : 'ul',

    initialize: function() {
        this.coll = new myCollection();
        this.coll.bind('add change',this.render,this);
    },

    events: {
        "click #add": "add"
    },

    add: function(e){
        e.preventDefault();
        var mod = new myModel();
        var name = $('#name').val();
        var link = $('#link').val();
        mod.set({'id':mod.cid, 'name':name,'link':link});                    
        this.coll.add(mod);

    },

    render : function(){

        $('#list').empty();
        this.coll.sort();
        this.coll.forEach(function(model){
            var listItem = new printView({ model: model});
            $('#list').append(listItem.render().el);
        });
    }
});

4.これは私のサブビューです。なぜ 2 つ目のビューを作成する必要があるのですか?なぜ 1 つのビューでは不十分なのですか? さて、これはシナリオを考えます。削除ボタンをクリックすると(たとえば)削除ボタンがあるすべてのリンクで(そして私は1つのビューしかありません)、どのモデルを破棄するかをどのように識別しますか(コレクションから削除しますか?)、1つの可能な方法を各モデルに関連付けてからcid、クリックすると this.coll.getByCid() を実行できますが、これはあまり良い方法ではないので、モデルごとに個別のビューを作成しました。このビューはレンダリングします各モデルを返し、それ以上は何も返しません。

var printView = Backbone.View.extend({

    tagName: 'li',

    initialize : function(options) {
        _.bindAll(this, "render");                   
    },

    events:{
        "click a": "count"
    },

    render:function(){
        var linkName = this.model.get("name");
        var link= this.model.get("link");
        var clicks = this.model.get("clicks");

        this.$el.append("<a class='link' href='"+link+"'>"+linkName+"</a> ("+clicks+")");

        return this;
    },

    count:function(e){
        e.preventDefault();
        e.stopPropagation();
        var clicks = this.model.get("clicks");
        clicks++;
        this.model.set({'clicks':clicks});
    }

});

5. (メイン) myView の初期化

new myView();

:このアプリケーション/コードは、いくつかの改善により、はるかに優れた方法で記述できると信じていますが、私の能力とそれが機能するという事実により(:p)、役立つと思います。

于 2013-02-08T19:42:56.723 に答える
2

コレクション コンパレータは、新しいモデルがコレクションに追加されたときにのみ実行されます。プロパティが変更されても、コレクションの順序は更新されません。これを実現するには、以下を呼び出す必要がありますcollection.sort()

App.Collections.Tasks = Backbone.Collection.extend({ 
    model: App.Models.Task,
    initialize: function() {
        this.on('change:counter', this.sort);
    },
    comparator: function(task) {
        return task.get('counter');
    }
});

リスト ビューでは、コレクションのsortイベントをリッスンし、ビューを再レンダリングできます。

App.Views.TasksView = Backbone.View.extend({
    tagName: 'ul',

    initialize: function() {
        this.collection.on('add', this.addOne, this);
        this.collection.on('sort', this.render, this);
        this.render();
    },

    render: function() {
        //if there are existing child views, remove them
        if(this.taskViews) {
            _.each(this.taskViews, function(view) {
                view.remove();
            });
        }
        this.taskViews = []; 
        this.collection.each(this.addOne, this);
        return this;
    },

    addOne: function(task) {
        var taskView = new App.Views.TaskView({ model: task });
        this.$el.append(taskView.render().el);

        //keep track of child views
        this.taskViews.push(taskView);
    }
});
于 2013-02-08T13:54:44.803 に答える