{"id":699,"date":"2022-08-30T15:05:42","date_gmt":"2022-08-30T15:05:42","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2013\/11\/09\/backbone-js-render-malfunctioning-after-being-removed-or-closed-collection-of-common-programming-errors\/"},"modified":"2022-08-30T15:05:42","modified_gmt":"2022-08-30T15:05:42","slug":"backbone-js-render-malfunctioning-after-being-removed-or-closed-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2022\/08\/30\/backbone-js-render-malfunctioning-after-being-removed-or-closed-collection-of-common-programming-errors\/","title":{"rendered":"Backbone.js Render Malfunctioning After Being Removed or Closed-Collection of common programming errors"},"content":{"rendered":"<p>I&#8217;ve extended Backbone&#8217;s View prototype to include a &#8220;close&#8221; function in order to &#8220;kill the zombies&#8221;, a technique I learned from Derrick Bailey&#8217;s blog<\/p>\n<p>The code looks like this:<\/p>\n<pre><code>Backbone.View.prototype.close = function () {\n    this.remove();\n    this.unbind();\n    if (this.onClose) {\n        this.onClose();\n    }\n};\n<\/code><\/pre>\n<p>Then I have a Router that looks (mostly) like this:<\/p>\n<pre><code>AppRouter = Backbone.Router.extend({\n\n    initialize: function() {\n        this.routesHit = 0;\n        \/\/keep count of number of routes handled by your application\n        Backbone.history.on('route', function () { this.routesHit++; }, this);\n    },\n\n    back: function () {\n        if(this.routesHit &gt; 1) {\n            \/\/more than one route hit -&gt; user did not land to current page directly\n            logDebug(\"going window.back\");\n            window.history.back();\n        } else {\n            \/\/otherwise go to the home page. Use replaceState if available so\n            \/\/the navigation doesn't create an extra history entry\n            this.navigate('\/', {trigger:true, replace:true});\n        }\n    },\n\n    routes: {\n        \"\": \"showLoginView\",\n        \"login\": \"showLoginView\",\n        \"signUp\": \"showSignUpView\"\n    },\n\n    showLoginView: function () {\n        view = new LoginView();\n        this.render(view);\n    },\n\n    showSignUpView: function () {\n        view = new SignUpView();\n        this.render(view);\n    },\n\n    render: function (view) {\n        if (this.currentView) {\n            this.currentView.close();\n        }\n        view.render();\n        this.currentView = view;\n        return this;\n    }\n});\n<\/code><\/pre>\n<p>The render function of my LoginView looks like this:<\/p>\n<pre><code>     render: function () {\n        $(\"#content\").html(this.$el.html(_.template($(\"#login-template\").html())));\n        this.delegateEvents();\n        return this;\n    }\n<\/code><\/pre>\n<p>The first time the LoginView is rendered, it works great. But if I render a different view (thereby calling &#8220;close&#8221; on my LoginView) and then try to go back to my LoginView, I get a blank screen. I know for a fact that the render on my LoginView fires the second time, but it seems that my &#8220;close&#8221; method is causing a problem. Any ideas?<\/p>\n<p><strong>EDIT<\/strong> After some feedback from Rayweb_on, it appears I should add more detail and clarify.<\/p>\n<p>My HTML looks like this:<\/p>\n<pre><code>this is my header\nI want my view to render in here\nthis is my footer\n<\/code><\/pre>\n<p>Then I have a login-template that looks like this (sort of):<\/p>\n<pre><code>\n        \n            \n               ...\n            \n        \n\n<\/code><\/pre>\n<p>I&#8217;m trying to get it so that the view always renders inside of that &#8220;content&#8221; div, but it appears that the call to &#8220;close&#8221; effectively removes the &#8220;content&#8221; div from the DOM. Hence the &#8220;blank&#8221; page. Any ideas?<\/p>\n<p><strong>EDIT 2<\/strong> Here&#8217;s what my LoginView looks like, after some noodling:<\/p>\n<pre><code>LoginView = Backbone.View.extend({\n    events: {\n        \"vclick #login-button\": \"logIn\"\n    },\n\n    el: \"#content\",\n\n    initialize: function () {\n        _.bindAll(this, \"logIn\");\n    },\n\n    logIn: function (e) {\n       ...\n    },\n\n\n    render: function () {\n        this.$el.html(_.template($(\"#login-template\").html()));\n        this.delegateEvents();\n        return this;\n    }\n\n});\n<\/code><\/pre>\n<p>I set the el to &#8220;#content&#8221; in the hopes that it would get recreated. But still no luck. In fact, now when I go to the next page it&#8217;s not there because #content is being removed right away.<\/p>\n<p>I also tried:<\/p>\n<pre><code>LoginView = Backbone.View.extend({\n    events: {\n        \"vclick #login-button\": \"logIn\"\n    },\n\n    el: \"#login-template\",\n\n    initialize: function () {\n        _.bindAll(this, \"logIn\");\n    },\n\n    logIn: function (e) {\n       ...\n    },\n\n\n    render: function () {\n        this.$el.html(_.template($(\"#login-template\").html()));\n        this.delegateEvents();\n        return this;\n    }\n\n});\n<\/code><\/pre>\n<p>But that doesn&#8217;t work at all. Any ideas?<\/p>\n<ol>\n<li>\n<p>It would appear that any elements included in the view get destroyed (or at least removed from the DOM) by my &#8220;close&#8221; function (thanks Rayweb_on!). So, if I reference the #content div in my view, I lose it after the view is closed. Therefore, I no longer reference #content anywhere in my view. Instead, I add my view&#8217;s default &#8220;el&#8221; to my #content element externally of my view.<\/p>\n<p>In my case, I chose to do it in my router. The result looks like this:<\/p>\n<p><strong>ROUTER<\/strong><\/p>\n<pre><code>    AppRouter = Backbone.Router.extend({\n\n    initialize: function() {\n     ...\n    },\n\n    routes: {\n        \"\" : \"showLoginView\",\n        \"login\": \"showLoginView\",\n        \"signUp\": \"showSignUpView\",\n    },\n\n    showLoginView: function () {\n        view = new LoginView();\n        this.render(view);\n    },\n\n    showSignUpView: function () {\n        view = new SignUpView();\n        this.render(view);\n    },\n\n    render: function (view)\n    {\n        if (currentView)\n        {\n            currentView.close();\n        }\n        $(\"#content\").html(view.render().el);\n        currentView = view;\n        return this;\n    }\n\n});\n<\/code><\/pre>\n<p><strong>LOGIN VIEW<\/strong><\/p>\n<pre><code>    LoginView = Backbone.View.extend({\n    events: {\n        \"vclick #login-button\": \"logIn\"\n    },\n\n    initialize: function () {\n        _.bindAll(this, \"logIn\");\n    },\n\n    logIn: function (e) {\n        ...\n    },\n\n    render: function () {\n        this.$el.html(_.template($(\"#login-template\").html()));\n        this.delegateEvents();\n        return this;\n    }\n\n});\n<\/code><\/pre>\n<p>This all works swimingly, but I am not certain it&#8217;s the best solution. I&#8217;m not even certain it&#8217;s a good solution, but it&#8217;ll get me moving for now. I&#8217;m certainly open to other options.<\/p>\n<p>====<\/p>\n<p><strong>EDIT:<\/strong> Found a slightly cleaner solution.<\/p>\n<p>I wrote a function called injectView that looks like this:<\/p>\n<pre><code>function injectView(view, targetSelector) {\n    if (_.isNull(targetSelector)) {\n        targetSelector = \"#content\";\n    }\n    $(targetSelector).html(view.el);\n}\n<\/code><\/pre>\n<p>and I call it from each View&#8217;s render function, like this:<\/p>\n<pre><code>        render: function () {\n        this.$el.html(_.template($(\"#login-template\").html()));\n        this.delegateEvents();\n        injectView(this,\"#content\")\n        return this;\n    }\n<\/code><\/pre>\n<p>It works. I don&#8217;t know how good it is. But it works.<\/p>\n<\/li>\n<li>\n<p>When you remove your view the first time you are removing its el, so this line<\/p>\n<pre><code> $(\"#content\").html(this.$el.html(_.template($(\"#login-template\").html())));\n<\/code><\/pre>\n<p>on your render function wont work. as this.$el. its undefined.<\/p>\n<\/li>\n<\/ol>\n<p id=\"rop\"><small>Originally posted 2013-11-09 21:40:15. <\/small><\/p>","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve extended Backbone&#8217;s View prototype to include a &#8220;close&#8221; function in order to &#8220;kill the zombies&#8221;, a technique I learned from Derrick Bailey&#8217;s blog The code looks like this: Backbone.View.prototype.close = function () { this.remove(); this.unbind(); if (this.onClose) { this.onClose(); } }; Then I have a Router that looks (mostly) like this: AppRouter = Backbone.Router.extend({ [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-699","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/699","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=699"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/699\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=699"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=699"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=699"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}