ব্যাকবোন.জেএস: দৃশ্যটি পুনরায় তৈরি বা পুনরায় তৈরি করুন?


83

আমার ওয়েব অ্যাপ্লিকেশনটিতে, আমার বামে একটি টেবিলের একটি ব্যবহারকারী তালিকা এবং ডানদিকে ব্যবহারকারীর বিশদ ফলক রয়েছে। প্রশাসক যখন কোনও ব্যবহারকারীকে টেবিলটিতে ক্লিক করেন, তার বিশদটি ডানদিকে প্রদর্শিত হবে।

আমার বাম দিকে একটি ইউজারলিস্টভিউ এবং ইউজাররউউউউ, এবং ডানদিকে একটি ইউজারডেটলভিউ রয়েছে। জিনিস কাজ ধরনের, কিন্তু আমার একটি অদ্ভুত আচরণ আছে। আমি যদি বাম দিকের কিছু ব্যবহারকারীকে ক্লিক করি তবে তার মধ্যে একটিতে মুছে ফেলতে ক্লিক করুন, আমি প্রদর্শিত হয়েছে এমন সমস্ত ব্যবহারকারীর জন্য ক্রমাগত জাভাস্ক্রিপ্ট কনফার্ম বক্সগুলি পাই।

দেখে মনে হচ্ছে পূর্বে প্রদর্শিত সমস্ত দর্শনগুলির ইভেন্টের বাইন্ডিংগুলি সরানো হয়নি, যা সাধারণ বলে মনে হচ্ছে। ইউজারআরভিউতে প্রতিবার নতুন ইউজারডেটলভিউ করা উচিত নয়? আমার কোন দৃষ্টিভঙ্গি বজায় রাখা উচিত এবং এর রেফারেন্স মডেলটি পরিবর্তন করা উচিত? আমার কি এখনকার দৃশ্যের উপর নজর রাখা উচিত এবং একটি নতুন চিত্র তৈরি করার আগে এটিকে সরিয়ে ফেলা উচিত? আমি একপ্রকার হারিয়েছি এবং যে কোনও ধারণা স্বাগত হবে। ধন্যবাদ !

এখানে বাম দৃশ্যের কোড (সারি প্রদর্শন, ক্লিক ইভেন্ট, ডান দৃশ্য তৈরি)

window.UserRowView = Backbone.View.extend({
    tagName : "tr",
    events : {
        "click" : "click",
    },
    render : function() {
        $(this.el).html(ich.bbViewUserTr(this.model.toJSON()));
        return this;
    },
    click : function() {
        var view = new UserDetailView({model:this.model})
        view.render()
    }
})

এবং ডান দেখার জন্য কোড (মুছুন বোতাম)

window.UserDetailView = Backbone.View.extend({
    el : $("#bbBoxUserDetail"),
    events : {
        "click .delete" : "deleteUser"
    },
    initialize : function() {
        this.model.bind('destroy', function(){this.el.hide()}, this);
    },
    render : function() {
        this.el.html(ich.bbViewUserDetail(this.model.toJSON()));
        this.el.show();
    },
    deleteUser : function() {
        if (confirm("Really delete user " + this.model.get("login") + "?")) 
            this.model.destroy();
        return false;
    }
})

উত্তর:


28

আমি সম্প্রতি এটি সম্পর্কে ব্লগ করেছি, এবং এই অ্যাপ্লিকেশনগুলিতে এই পরিস্থিতিগুলি পরিচালনা করতে আমি বেশ কয়েকটি জিনিস দেখিয়েছি:

http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/


4
শুধু delete viewরাউটারে কেন নয় ?
ট্র্যান্টর লিউ

আমি আপনার উত্তরটি উন্নত করেছিলাম, তবে এটি এখানে লক্ষ্য হিসাবে উত্তরটি নিজেরাই ব্লগ পোস্টের সম্পর্কিত অংশগুলি পেয়ে সত্যিকার অর্থে উপকৃত হবে।
এমিল বার্গারন

136

আমি সর্বদা ধ্বংস করে দেখি এবং তৈরি করি কারণ আমার একক পৃষ্ঠার অ্যাপটি আরও বড় হয়ে ওঠে, অব্যবহৃত লাইভ ভিউগুলিকে স্মৃতিতে রেখে দেয় যাতে আমি সেগুলি পুনরায় ব্যবহার করতে পারি যাতে এটি বজায় রাখা কঠিন হয়ে যায়।

এখানে এমন কোনও প্রযুক্তির একটি সরলিকৃত সংস্করণ যা আমি মেমরির ফাঁস এড়াতে আমার ভিউগুলি সাফ করার জন্য ব্যবহার করি।

আমি প্রথমে একটি বেসভিউ তৈরি করি যা আমার সমস্ত দর্শন থেকে উত্তরাধিকার সূত্রে প্রাপ্ত। মূল ধারণাটি হ'ল আমার দৃশ্যের সাথে এটিতে সাবস্ক্রাইব হওয়া সমস্ত ইভেন্টের একটি রেফারেন্স রাখবে, যাতে যখন ভিউটি নিষ্পত্তি করার সময় আসে তখন সমস্ত বাঁধাই স্বয়ংক্রিয়ভাবে সীমাহীন হয়ে যায়। এখানে আমার বেসভিউয়ের উদাহরণ বাস্তবায়ন:

var BaseView = function (options) {

    this.bindings = [];
    Backbone.View.apply(this, [options]);
};

_.extend(BaseView.prototype, Backbone.View.prototype, {

    bindTo: function (model, ev, callback) {

        model.bind(ev, callback, this);
        this.bindings.push({ model: model, ev: ev, callback: callback });
    },

    unbindFromAll: function () {
        _.each(this.bindings, function (binding) {
            binding.model.unbind(binding.ev, binding.callback);
        });
        this.bindings = [];
    },

    dispose: function () {
        this.unbindFromAll(); // Will unbind all events this view has bound to
        this.unbind();        // This will unbind all listeners to events from 
                              // this view. This is probably not necessary 
                              // because this view will be garbage collected.
        this.remove(); // Uses the default Backbone.View.remove() method which
                       // removes this.el from the DOM and removes DOM events.
    }

});

BaseView.extend = Backbone.View.extend;

যখনই কোনও ভিউর কোনও মডেল বা সংগ্রহের কোনও ইভেন্টের সাথে আবদ্ধ হওয়ার প্রয়োজন হয়, আমি বাইন্ডটো পদ্ধতিটি ব্যবহার করতাম। উদাহরণ স্বরূপ:

var SampleView = BaseView.extend({

    initialize: function(){
        this.bindTo(this.model, 'change', this.render);
        this.bindTo(this.collection, 'reset', this.doSomething);
    }
});

আমি যখনই কোনও দৃশ্য সরিয়ে ফেলি, তখন আমি কেবল নিষ্পত্তি পদ্ধতিটি কল করি যা সমস্ত কিছু স্বয়ংক্রিয়ভাবে পরিষ্কার হয়ে যাবে:

var sampleView = new SampleView({model: some_model, collection: some_collection});
sampleView.dispose();

আমি এই কৌশলটি লোকদের সাথে ভাগ করে নিলাম যারা "ব্যাকবোন.জস অন রেইল" ইবুক লিখছেন এবং আমি বিশ্বাস করি এটি এই কৌশলটি যা তারা বইটির জন্য গ্রহণ করেছিলেন।

আপডেট: 2014-03-24

ব্যাকন 0.9.9 হিসাবে, উপরে বর্ণিত একই বাইনডটো এবং আনবাইন্ডফ্র্যামআল কৌশলগুলি ব্যবহার করে ইভেন্টগুলিতে লিসটো এবং স্টপলাইস্টিং যুক্ত করা হয়েছিল। এছাড়াও, ভিউ.রিমোভ স্টপলিস্টিংকে স্বয়ংক্রিয়ভাবে কল করে, তাই বাঁধাই এবং আনবাইন্ডিং এখনকার মতো সহজ:

var SampleView = BaseView.extend({

    initialize: function(){
        this.listenTo(this.model, 'change', this.render);
    }
});

var sampleView = new SampleView({model: some_model});
sampleView.remove();

নেস্টেড মতামতগুলি নিষ্পত্তি করার জন্য আপনার কী কোনও পরামর্শ আছে? এই মুহূর্তে আমি বাইন্ডটো: gist.github.com/1288947 এর মতোই করছি তবে আমি অনুমান করি যে আরও ভাল কিছু করা সম্ভব।
দিমিত্রি পলুশকিন

দিমিত্রি, নেস্টেড মতামত নিষ্পত্তি করতে আপনি যা করছেন তার অনুরূপ আমিও কিছু করি। আমি এখনও এর চেয়ে ভাল সমাধান দেখতে পাইনি, তবে এর একটি আছে কিনা তা জানতে আগ্রহীও হব। এখানে আরও একটি আলোচনা যা এটিরও স্পর্শ করে: গ্রুপ . google.com/forum/#!topic/backbonejs/3ZFm-lteN-A । আমি লক্ষ্য করেছি যে আপনার সমাধানে, আপনি যেখানে নেস্টেড ভিউ সরাসরি নিষ্পত্তি হবে সেই দৃশ্যের বিষয়টি বিবেচনায় নিচ্ছেন না। এই জাতীয় পরিস্থিতিতে, নেস্টেড ভিউ নিষ্পত্তি করা সত্ত্বেও প্যারেন্ট ভিউ নেস্টেড ভিউয়ের একটি রেফারেন্স রাখবে। আপনার যদি এটির জন্য অ্যাকাউন্ট দরকার হয় তা আমি জানি না।
জনি ওশিকা

যদি আমার কার্যকারিতা থাকে যা একই দৃষ্টিভঙ্গিটি খোলে এবং বন্ধ করে দেয়। আমার একটি ফরোয়ার্ড এবং পিছনের বোতাম রয়েছে। আমি যদি ডিসপোজ কল করি তবে এটি ডিওএম থেকে উপাদানটি সরিয়ে ফেলবে। আমার কি পুরো সময়টি স্মৃতিতে রাখা উচিত?
দাগদা

4
হাই ফিশারভেদেব। আপনি ব্যাকবোন.ভিউ.একসেটের সাহায্যে এই কৌশলটিও ব্যবহার করতে পারেন, তবে আপনাকে বেসভিউ.ইনইটিয়ালাইজ পদ্ধতিতে এই.বাইন্ডিংগুলি শুরু করতে হবে। এটির সাথে সমস্যাটি হ'ল যদি আপনার উত্তরাধিকার সূত্রে দেখা তার নিজস্ব প্রারম্ভিক পদ্ধতিটি প্রয়োগ করে, তবে এটিকে স্পষ্টভাবে বেসভিউয়ের আরম্ভ পদ্ধতিটি কল করতে হবে। আমি এই সমস্যাটি আরও বিশদে এখানে ব্যাখ্যা করেছি: stackoverflow.com/a/7736030/188740
জনি ওশিকা

4
হাই সানিআরেড, আমার দৃষ্টিভঙ্গিগুলি ধ্বংস করার কারণটি আরও ভালভাবে প্রতিবিম্বিত করতে আমি আমার উত্তর আপডেট করেছি। ব্যাকবোন দিয়ে, আমি কোনও অ্যাপ্লিকেশন শুরু হওয়ার পরে কোনও পৃষ্ঠা পুনরায় লোড করার কোনও কারণ দেখতে পাচ্ছি না, তাই আমার একক পৃষ্ঠার অ্যাপটি বেশ বড় হয়েছে। ব্যবহারকারীরা আমার অ্যাপ্লিকেশনের সাথে ইন্টারঅ্যাক্ট করার সাথে সাথে আমি ক্রমাগত পৃষ্ঠার বিভিন্ন বিভাগকে পুনরায় রেন্ডার করছি (উদাহরণস্বরূপ সম্পাদনা করার জন্য বিশদ থেকে স্যুইচ করা), তাই এই বিভাগটি আগে রেন্ডার করা হয়েছিল কিনা তা নির্বিশেষে আমি সর্বদা নতুন দৃষ্টিভঙ্গি তৈরি করা অনেক সহজ মনে করি or না. অন্যদিকে মডেলগুলি ব্যবসায়িক অবজেক্টগুলিকে প্রতিনিধিত্ব করে, সুতরাং আমি কেবল তখনই তাদের সংশোধন করব যদি বস্তুটি সত্যই পরিবর্তিত হয়।
জনি ওশিকা

8

এটি একটি সাধারণ অবস্থা। আপনি যদি প্রতিবার নতুন ভিউ তৈরি করেন তবে সমস্ত পুরানো দর্শন এখনও সমস্ত ইভেন্টের সাথে আবদ্ধ থাকবে। আপনি যা করতে পারেন তা হ'ল আপনার ভিউতে একটি ফাংশন তৈরি করুন detatch:

detatch: function() {
   $(this.el).unbind();
   this.model.unbind();

তারপরে, আপনি নতুন ভিউ তৈরি করার আগে, detatchপুরানো ভিউতে কল করতে ভুলবেন না ।

অবশ্যই, আপনি যেমনটি উল্লেখ করেছেন, আপনি সর্বদা একটি "বিশদ" দর্শন তৈরি করতে পারেন এবং এটি কখনই পরিবর্তন করতে পারবেন না। নিজেকে পুনরায় রেন্ডার করতে আপনি মডেলটিতে "পরিবর্তন" ইভেন্টের সাথে আবদ্ধ হতে পারেন। এটি আপনার আরম্ভকারীতে যুক্ত করুন:

this.model.bind('change', this.render)

এটি করার ফলে মডেলটিতে পরিবর্তন আসার পরে বিশদগুলি বিশদটি পুনরায় রেন্ডার করবে। আপনি একটি একক সম্পত্তি দেখে ভালতর গ্রানুলারিটি পেতে পারেন: "পরিবর্তন: প্রোপনাম"।

অবশ্যই এটি করার জন্য একটি সাধারণ মডেল প্রয়োজন যা আইটেম ভিউয়ের সাথে সাথে উচ্চ স্তরের তালিকার ভিউ এবং বিশদ দর্শন উল্লেখ রয়েছে।

আশাকরি এটা সাহায্য করবে!


4
হুম, আপনার পরামর্শ অনুসারে আমি কিছু করেছি, তবে আমার এখনও সমস্যা আছে: উদাহরণস্বরূপ, this.model.unbind()আমার পক্ষে এটি ভুল কারণ এটি একই ব্যবহারকারীর অন্যান্য মতামত সম্পর্কিত ইভেন্টগুলি সহ এই মডেল থেকে সমস্ত ইভেন্টকে আবদ্ধ করে। তদ্ব্যতীত, detachফাংশনটি কল করার জন্য , আমার দৃষ্টিভঙ্গির স্থিতিশীল রেফারেন্স রাখা দরকার এবং আমি এটি পছন্দ করি না। আমি সন্দেহ করি যে এখনও এমন কিছু আছে যা আমি বুঝতে পারি না ...
12:25

6

একাধিকবার বাধ্যতামূলক ইভেন্টগুলি ঠিক করতে,

$("#my_app_container").unbind()
//Instantiate your views here

রুট থেকে নতুন ভিউগুলি তাত্ক্ষণিক করার আগে উপরের লাইনটি ব্যবহার করে জম্বি ভিউগুলি সহ আমার যে সমস্যাটি ছিল তা সমাধান করে।


এখানে খুব ভাল, বিস্তারিত উত্তর রয়েছে। আমি অবশ্যই ViewManger এর কয়েকটি পরামর্শ সন্ধান করার ইচ্ছা করি। যাইহোক, এটি এক সাধারণ মরে গিয়েছিল এবং এটি আমার পক্ষে নিখুঁতভাবে কাজ করে কারণ আমার দর্শনগুলি বন্ধ () পদ্ধতিযুক্ত সমস্ত প্যানেল, যেখানে আমি কেবল ইভেন্টগুলি আবদ্ধ করতে পারি। ধন্যবাদ আশান
নেটপেটিকা

4
আমি আনবাইন্ড করার পরে পুনরায় রেন্ডার করব না বলে মনে হচ্ছে: \
কোডগুরু

@ ফ্লাইংআটম: এমনকি আমি আনবাইন্ডিংয়ের পরে পুনরায় রেন্ডার করতে সক্ষম হচ্ছি না। আপনি কি কোনও উপায় খুঁজে পেয়েছেন?
রাইসা

দেখুন $ এল.রেমোডেটা ()। আনবাইন্ড ();
আলেকজান্ডার মিলস

2

আমি মনে করি ব্যাকবোন দিয়ে শুরু করা বেশিরভাগ লোকেরা আপনার কোডের মতোই ভিউ তৈরি করবে:

var view = new UserDetailView({model:this.model});

এই কোডটি জম্বি ভিউ তৈরি করে, কারণ আমরা সম্ভবত উপস্থিত ভিউ ক্লিনআপ ছাড়াই নিয়মিত নতুন ভিউ তৈরি করতে পারি। তবে আপনার অ্যাপ্লিকেশনে সমস্ত ব্যাকবোন ভিউয়ের জন্য ভিউ.ডিস্পোজ () কল করা সুবিধাজনক নয় (বিশেষত যদি আমরা লুপের জন্য ভিউ তৈরি করি)

আমি মনে করি ক্লিনআপ কোড দেওয়ার সর্বোত্তম সময়টি নতুন ভিউ তৈরির আগে। আমার সমাধান হ'ল এই ক্লিনআপটি করতে কোনও সহায়ক তৈরি করা:

window.VM = window.VM || {};
VM.views = VM.views || {};
VM.createView = function(name, callback) {
    if (typeof VM.views[name] !== 'undefined') {
        // Cleanup view
        // Remove all of the view's delegated events
        VM.views[name].undelegateEvents();
        // Remove view from the DOM
        VM.views[name].remove();
        // Removes all callbacks on view
        VM.views[name].off();

        if (typeof VM.views[name].close === 'function') {
            VM.views[name].close();
        }
    }
    VM.views[name] = callback();
    return VM.views[name];
}

VM.reuseView = function(name, callback) {
    if (typeof VM.views[name] !== 'undefined') {
        return VM.views[name];
    }

    VM.views[name] = callback();
    return VM.views[name];
}

আপনার ভিউ তৈরি করতে ভিএম ব্যবহার করে ভিউ.ডিস্পজ () কল না করে যে কোনও বিদ্যমান ভিউ পরিষ্কার করতে সহায়তা করবে। আপনি নিজের কোড থেকে একটি ছোট পরিবর্তন করতে পারেন

var view = new UserDetailView({model:this.model});

প্রতি

var view = VM.createView("unique_view_name", function() {
                return new UserDetailView({model:this.model});
           });

সুতরাং আপনি যদি দেখার বিষয়টিকে অবিচ্ছিন্নভাবে তৈরির পরিবর্তে পুনরায় ব্যবহার করতে চান তবে যতক্ষণ না দৃষ্টি পরিষ্কার থাকে ততক্ষণ আপনার চিন্তা করার দরকার নেই। পুনঃব্যবস্থাতে শুধু ক্রিয়েভিউ পরিবর্তন করুন:

var view = VM.reuseView("unique_view_name", function() {
                return new UserDetailView({model:this.model});
           });

বিস্তারিত কোড এবং এ্যাট্রিবিউশন পোস্ট করা হয়েছে https://github.com/thomasdao/Backbone- ভিউ- ম্যানেজারে


আমি ইদানীং ব্যাকবোনটির সাথে ব্যাপকভাবে কাজ করে যাচ্ছি এবং এটি জুম্বি ভিউগুলি পরিচালনা করার বা দৃশ্যের পুনর্বার ব্যবহার করার সময় সর্বাধিক ঝলমলে উপায় বলে মনে হচ্ছে। আমি সাধারণত ডেরিক বেইলের উদাহরণ অনুসরণ করি তবে এই ক্ষেত্রে এটি আরও নমনীয় বলে মনে হয়। আমার প্রশ্ন, আরও বেশি লোক কেন এই কৌশলটি ব্যবহার করছেন না?
এমএফডি 3000

কারণ তিনি ব্যাকবোন :) এর বিশেষজ্ঞ because আমি মনে করি এই কৌশলটি বেশ সহজ এবং ব্যবহার করা বেশ নিরাপদ, আমি এটি ব্যবহার করে আসছি এবং এখন পর্যন্ত কোনও সমস্যা নেই :)
থোমাসডাও

0

একটি বিকল্প বাঁধাই, যেমন নতুন নতুন মতামত তৈরি করা এবং তারপরে এই মতামতগুলিকে আবদ্ধ করার বিপরীতে। আপনি এই কাজটি করতে এমন কিছু করতে সক্ষম হবেন:

window.User = Backbone.Model.extend({
});

window.MyViewModel = Backbone.Model.extend({
});

window.myView = Backbone.View.extend({
    initialize: function(){
        this.model.on('change', this.alert, this); 
    },
    alert: function(){
        alert("changed"); 
    }
}); 

আপনি আমারভিউর মডেলটি আমার ভিউমোডেলে সেট করেছেন, যা কোনও ব্যবহারকারী মডেলকে সেট করা হবে। এইভাবে, আপনি যদি অন্য ব্যবহারকারীর সাথে মাইভিউমোডেল সেট করেন (যেমন, এর বৈশিষ্ট্যগুলি পরিবর্তন করে) তবে এটি নতুন বৈশিষ্ট্যগুলির সাথে ভিউতে একটি রেন্ডার ফাংশনটিকে ট্রিগার করতে পারে।

একটি সমস্যা হ'ল এটির মূল মডেলের লিঙ্কটি ভেঙে। আপনি সংগ্রহ সংগ্রহ অবজেক্টটি ব্যবহার করে বা ভিউমডেলের একটি বৈশিষ্ট্য হিসাবে ব্যবহারকারী মডেলটিকে সেট করে এটি পেতে পারেন। তারপরে, এটি myview.model.get ("মডেল") হিসাবে ভিউতে অ্যাক্সেসযোগ্য হবে।


4
দূষিত বৈশ্বিক সুযোগ কখনই একটি ভাল ধারণা নয়। আপনি কেন উইন্ডোটির নেমস্পেসে বিবি.মোডেলস এবং বিবি.ভিউগুলি ইনস্ট্যান্ট করবেন?
ভার্নন

0

সন্তানের দৃষ্টিভঙ্গি এবং মেমরি থেকে বর্তমান মতামতগুলি সাফ করার জন্য এই পদ্ধতিটি ব্যবহার করুন।

//FIRST EXTEND THE BACKBONE VIEW....
//Extending the backbone view...
Backbone.View.prototype.destroy_view = function()
{ 
   //for doing something before closing.....
   if (this.beforeClose) {
       this.beforeClose();
   }
   //For destroying the related child views...
   if (this.destroyChild)
   {
       this.destroyChild();
   }
   this.undelegateEvents();
   $(this.el).removeData().unbind(); 
  //Remove view from DOM
  this.remove();  
  Backbone.View.prototype.remove.call(this);
 }



//Function for destroying the child views...
Backbone.View.prototype.destroyChild  = function(){
   console.info("Closing the child views...");
   //Remember to push the child views of a parent view using this.childViews
   if(this.childViews){
      var len = this.childViews.length;
      for(var i=0; i<len; i++){
         this.childViews[i].destroy_view();
      }
   }//End of if statement
} //End of destroyChild function


//Now extending the Router ..
var Test_Routers = Backbone.Router.extend({

   //Always call this function before calling a route call function...
   closePreviousViews: function() {
       console.log("Closing the pervious in memory views...");
       if (this.currentView)
           this.currentView.destroy_view();
   },

   routes:{
       "test"    :  "testRoute"
   },

   testRoute: function(){
       //Always call this method before calling the route..
       this.closePreviousViews();
       .....
   }


   //Now calling the views...
   $(document).ready(function(e) {
      var Router = new Test_Routers();
      Backbone.history.start({root: "/"}); 
   });


  //Now showing how to push child views in parent views and setting of current views...
  var Test_View = Backbone.View.extend({
       initialize:function(){
          //Now setting the current view..
          Router.currentView = this;
         //If your views contains child views then first initialize...
         this.childViews = [];
         //Now push any child views you create in this parent view. 
         //It will automatically get deleted
         //this.childViews.push(childView);
       }
  });
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.