Can't delete Backbone.View causing zombies - backbone.js

I can't seem to completely destroy my Backbone.Views. I have tried all the suggestions and still they turn into zombies and start an apocalypse on my memory. Please tell me what I am doing wrong.
When I toggle back and forth between routes /access and /settings the browser creates new instances as expected, the close method fires and completes, however the profiler in chrome says something the previous instances are hanging around.
My BaseView
class BaseView extends Backbone.View
# -------------------------------------------
isRendered: false
autoDestroy: false
# -------------------------------------------
close: ->
log 'Closing View', #, #model
#onClose() if #onClose?
#remove() if #?
#unbind() if #? # Unbind all local event bindings
delete #$el # Delete the jQuery wrapped object variable
delete #el # Delete the variable reference to this node
delete #
log 'Everything is destroyed', #
# -------------------------------------------
module.exports = BaseView
My Router
class Router extends BaseRouter
name: "Router"
container: "#content-container"
routes: routes
#----------------------
access: (slug) ->
AccessPage = require '../view/page/access-page.coffee'
accessPage = new AccessPage()
accessPage.render()
#showPage accessPage
#----------------------
settings: (slug) ->
SettingsPage = require '../view/page/settings-page.coffee'
settingsPage = new SettingsPage()
settingsPage.render()
#showPage settingsPage
My BaseRouter
class BaseRouter extends Backbone.Router
currentPageView: null
pageClass: '.page'
# -------------------------------------------
showPage: (view, hidePages = true) ->
#hideAllPages() if hidePages
#currentPageView = view
$(#container).append view.$el
log 'showPage', view.$el
view.$el.show()
# -------------------------------------------
hideAllPages: ->
if #currentPageView?.onHide?
#currentPageView.onHide()
if #currentPageView? and #currentPageView.autoDestroy
#currentPageView.close()
$(#pageClass).hide()
One of my Views
class AccessPage extends BaseView
name: "AccessPage"
id: "access-page"
autoDestroy: true
className: 'page'
#----------------------
initialize: ->
log #name, "initialize"
#----------------------
render: ->
log #name, "render"
#$el.html template
title: "Access"
#isRendered = true
#----------------------
module.exports = AccessPage

Related

How do I complete this PureScript pushState routing example?

I'm trying to do pushState routing in PureScript, using the purescript-routing library. To help work it out, I've built the following minimal example:
module Main where
import Prelude
import Data.Foldable (oneOf)
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow)
import Effect (Effect)
import Effect.Console (log)
import Flame (Html, QuerySelector(..))
import Flame.Application.NoEffects as FAN
import Flame.HTML.Attribute as HA
import Flame.HTML.Element as HE
import Routing.Match (Match, end, int, lit, root)
import Routing.PushState (makeInterface, matches)
import Signal.Channel (send)
type Model = {
route :: Route
}
data Message = ChangeRoute Route
data Route
= RouteOne
| RouteTwo
| RouteThree Int
| Root
derive instance genericRoute :: Generic Route _
instance showRoute :: Show Route where
show = genericShow
route :: Match Route
route = root *> oneOf
[ Root <$ end
, RouteOne <$ lit "route-1" <* end
, RouteTwo <$ lit "route-2" <* end
, RouteThree <$> (lit "route-3" *> int)
]
init :: Model
init = { route: Root }
update :: Model -> Message -> Model
update model = case _ of
ChangeRoute x -> model { route = x }
view :: Model -> Html Message
view model = HE.main "main" $
[ HE.p_ ("Route: " <> show model.route)
, HE.ul_
[ HE.li_
[ HE.a [ HA.href "/route-1" ] "route 1"
]
, HE.li_
[ HE.a [ HA.href "/route-2" ] "route 2"
]
, HE.li_
[ HE.a [ HA.href "/route-3/123" ] "route 3"
]
]
]
main :: Effect Unit
main = do
nav <- makeInterface
flameChannel <- FAN.mount (QuerySelector "main")
{ init
, update
, view
}
void $ nav # matches route \oldRoute newRoute -> do
log $ show oldRoute <> " -> " <> show newRoute
send flameChannel [ ChangeRoute newRoute ]
What works:
Route parsing
Printing the current route in the console
What doesn't work: Clicking a link in the DOM is handled by a page load, instead of a signal being sent to the application.
What code changes/additions need to be made so clicking a link results in a signal being sent to Flame, as opposed to a browser page load? Is my general approach even correct?
I've tried using the purescript-routing documentation and purescript-routing tests to gain an understanding, but neither show a complete example (including clickable URLs). I have also tried working from the RoutingPushHalogenClassic PureScript cookbook code, but it doesn't seem applicable to Flame.
This is one way to complete it:
module Main where
import Prelude
import Data.Foldable (oneOf)
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow)
import Data.Maybe (Maybe(..), isNothing)
import Debug.Trace (spy)
import Effect (Effect)
import Effect.Console (log)
import Flame (Html, QuerySelector(..))
import Flame.Application.NoEffects as FAN
import Flame.HTML.Attribute as HA
import Flame.HTML.Element as HE
import Foreign (unsafeToForeign)
import Routing.Match (Match, end, int, lit, root)
import Routing.PushState (PushStateInterface, makeInterface, matches)
import Signal.Channel (Channel, send)
import Web.Event.Event (preventDefault)
type Model
= { navInterface :: PushStateInterface
, route :: Route
}
data Message
= ChangeRouteInternal Route
| ChangeRouteExternal Route
data Route
= RouteOne
| RouteTwo
| RouteThree Int
| Root
derive instance genericRoute :: Generic Route _
instance showRoute :: Show Route where
show = genericShow
route :: Match Route
route =
root
*> oneOf
[ Root <$ end
, RouteOne <$ lit "route-1" <* end
, RouteTwo <$ lit "route-2" <* end
, RouteThree <$> (lit "route-3" *> int) <* end
]
init :: PushStateInterface -> Model
init nav = { navInterface: nav, route: Root }
update :: Model -> Message -> Model
update model = case _ of
ChangeRouteInternal x -> spy "ChangeRouteInternal" model { route = x }
ChangeRouteExternal x -> spy "ChangeRouteExternal" model { route = x }
view :: Model -> Html Message
view model =
HE.main "main"
$ [ HE.p_ ("Route: " <> show model.route)
, HE.ul_
[ HE.li_
[ HE.a (routeAnchorAttributes (ChangeRouteInternal RouteOne)) "route 1"
]
, HE.li_
[ HE.a (routeAnchorAttributes (ChangeRouteInternal RouteTwo)) "route 2"
]
, HE.li_
[ HE.a (routeAnchorAttributes (ChangeRouteInternal (RouteThree 123))) "route 3"
]
]
]
where
routeAnchorAttributes = case _ of
ChangeRouteInternal anchorRoute -> [ HA.href (routeToUrl anchorRoute), onClick_ anchorRoute ]
_ -> []
-- Based on keypress example at:
-- https://github.com/easafe/purescript-flame/blob/master/test/Basic/EffectList.purs
onClick_ clickedRoute =
HA.createRawEvent "click"
$ \event -> do
preventDefault event
model.navInterface.pushState (unsafeToForeign {}) (routeToUrl clickedRoute)
pure $ Just (ChangeRouteInternal clickedRoute)
routeToUrl :: Route -> String
routeToUrl = case _ of
Root -> "/"
RouteOne -> "/route-1"
RouteTwo -> "/route-2"
RouteThree n -> "/route-3/" <> (show n)
routeMatch :: Match Route -> Channel (Array Message) -> PushStateInterface -> Effect Unit
routeMatch m chan =
void
<$> matches m \oldRoute newRoute -> do
log $ show oldRoute <> " -> " <> show newRoute
if isNothing oldRoute then
send chan [ ChangeRouteExternal newRoute ]
else
pure unit
main :: Effect Unit
main = do
nav <- makeInterface
flameChannel <-
FAN.mount (QuerySelector "main")
{ init: init nav
, update
, view
}
routeMatch route flameChannel nav
This code has separate Message concrete types for route changes originating from inside the application versus outside, i.e. from the user typing in the address bar, loading the application from an external link, etc. This is not necessary, but I wanted to highlight that the logic and code paths for these circumstances are different.
routeMatch handles external routing changes, onClick_ is for internal and uses Flame's own createRawEvent function.
While the Flame docs don't cover click handling and preventDefault, I did find this test of key capture very helpful when making onClick_.
Open the developer tools console to see messages and internal state changes.

Kibana 6.1.1 Custom Plugin (visualization)

I'm pretty new to Kibana, and I'm trying to make my own visualization custom plugin (for kibana 6.1.1).
At that moment I just want to see something on the screen that says "hello world" or something.
Firstly, this is my folder structure:
.
├── package.json
├── public
| ├── mainTemplate.html
| ├── optionTemplate.html
| ├── mortaController.js
| └── morta.js
├── index.js
This is morta.js looks like:
import 'plugins/morta/mortaController';
//core methods
import {CATEGORY} from 'ui/vis/vis_category';
import {VisFactoryProvider} from 'ui/vis/vis_factory';
import {VisSchemasProvider} from 'ui/vis/editors/default/schemas';
import {VisTypesRegistryProvider} from 'ui/registry/vis_types';
//templates
import mainTemplate from 'plugins/morta/mainTemplate.html';
import optionTemplate from 'plugins/morta/optionTemplate.html';
VisTypesRegistryProvider.register(MortaProvider);
function MortaProvider(Private) {
const VisFactory = Private(VisFactoryProvider);
const Schemas = Private(VisSchemasProvider);
return VisFactory.createAngularVisualization({
name: "morta",
title: "Morta Vis",
icon: "fa-terminal",
description: "Morta visualization",
category: CATEGORY.BASIC,
visConfig: {
defaults: {},
template: mainTemplate
},
editorConfig: {
optionsTemplate: optionTemplate,
schemas: new Schemas([{
group: 'metrics',
name: 'test_metrics',
title: "Testing metrics",
min: 1,
max: 1,
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality', 'std_dev'],
defaults: [
{schema: 'metric', type: 'count'}
]
}])
}
});
}
export default MortaProvider;
This is my controller:
import { uiModules } from 'ui/modules';
const module = uiModules.get('morta', ['kibana']);
module.controller('MortaController', mortaController);
mortaController.$inject = ['$scope'];
function mortaController($scope){
let vm = this;
}
This is the mainTemplate:
<div data-ng-controller="MortaController as vm">
<h1>Morta Visualize View</h1>
</div>
This is the optionTemplate:
<p>Test Options</p>
I've got my kibana and elasticsearch servers up and running, then i'm trying to create a new visualization with my custom plugin but i'm getting an error saying :
"Visualize: cannot read property 'group' of undefined"
I'm not sure if I'm missing something or doing something wrong, let me know if you need more information that I can provide.
This can happen in the create visualization screen after changing the name and forcing a refresh.
name: 'test_metrics',
Exit out of the 'create visualization' screen e.g. click the 'visualize' tab, and the '+' create visualization button to get back to where you were
This worked for me (on version 6.3.2)

Create unique instance of provider ionic 3

I am creating an Ionic app. I have 3 providers - database provider, portfolio provider and user provider. All 3 are Injectable. I have created it this way because several other pages need to use their function calls (i.e. they should not share the same data, they all should create new instances)
Both the portfolio and user provider import the database provider, as the need to make the same database calls to retrieve data.
I have 1 page - ViewPortfolio. The ViewPortfolio page imports the user provider (to know who the user is) and portfolio provider (to get the users portfolio data). For some reason, these 2 providers seem to be sharing the same instance for database provider. This is how I use them:
PORTFOLIO PROVIDER
import { DatabaseProvider } from '../providers/database-provider';
#Injectable()
#Component({
providers: [DatabaseProvider]
})
export class PortfolioProvider {
public portfolio_list: any = new BehaviorSubject<Array<string>>([]);
constructor(private dbProvider: DatabaseProvider) {
this.dbProvider.enableDataListener(this.protfolio_path); // set path
this.dbProvider.db_listener.subscribe(value => { // subscribe to data in the path
// do stuff
});
}
}
The user portfolio is the same, the only difference is the path its listening to is different.
However, when I change data in the portfolio path, the subscribe call is also triggered in the user path (and vice versa). Thus, even though I added DatabaseProvider in the components providers, its not creating unique instances. Why is this?
I figured it might be because I am importing them both on the same page but I am not convinced that's why it is not working. How do I make the 2 providers use unique instances on databaseprovider, while calling them both on the same page?
This is what my app.moudle.ts file looks like (please note that DatabaseProvider is not included in my app.module.ts file)
// ... more imports
import { PortfolioProvider } from '../providers/portfolio-provider';
import { UserProvider } from '../providers/user-provider';
#NgModule({
declarations: [
MyApp,
// ... more
],
imports: [
// ... more
IonicModule.forRoot(MyApp, {
backButtonText: '',
tabsPlacement: 'bottom'
}),
IonicStorageModule.forRoot()
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
// ... more
],
providers: [
// ... more
PortfolioProvider,
UserProvider
]
})
export class AppModule {}
Thanks,
Did you remove the provider from app.module.ts (root AppModule)?
From the Angular Documentation:
Scenario: service isolation
While you could provide VillainsService in the root AppModule (that's where you'll find the HeroesService), that would make the VillainsService available everywhere in the application, including the Hero workflows.
If you generated the provider using ionic-cli, it'll automatically add it to the root AppModule.

Marionette Module using typescript

How to create marionete module using type script. I saw this how to write marionettejs module using typescript? but its not usefull for my case. I created module like
class TestModule extends Marionette.Module {
constructor(options) {
if (!options)
options = {};
var marionetteApp = new MarionetteApp();
marionetteApp.module("myModule", {
startWithParent: false
});
super("myModule", marionetteApp);
}
}
but its shows error
Unhandled exception at line 3561, column 5 in http://localhost/Scripts/backbone.marionette.js
0x800a138f - JavaScript runtime error: Unable to get property 'initialize' of undefined or null reference
What Im doing wrong. I am new to Marionette and typescript. What is the correct procedure to create marionette module using typescript
My application code is
class MarionetteApp extends Marionette.Application {
headerRegion: Marionette.Region;
leftRegion: Marionette.Region;
centerRegion: Marionette.Region;
constructor() {
super();
this.on("start", this.initializeAfter);
this.addRegions({ headerRegion:"#headerContainer",leftRegion:"#leftContainer",centerRegion:"#centerContainer"});
}
initializeAfter() {
//alert("started")
this.headerRegion.show(new HeaderView());
this.leftRegion.show(new leftView());
this.centerRegion.show(new CenterView());
var MyModule = new TestModule("Test");
//MyModule.start();
}
}
I fixed the issue using following code. Wrapped module inside a class. Its working as expected. Please correct me if I am wrong and anyone knows the correct procedure
class TestModule {
mod: any;
constructor() {
var marionetteApp = new MarionetteApp();
this.mod = marionetteApp.module("myModule", {
startWithParent: false,
initialize: function(){
console.log("initialized");
},
define: function () {
console.log("defined");
}
});
this.mod.on("start", this.onStart);
}
start() {
this.mod.start();
}
onStart() {
console.log("Module started")
}
}
initialization code
var MyModule = new TestModule();
MyModule.start();

BackboneJS, MarionetteJS - Trying to display layout + regions

I've got the following code
$ ->
class MainLayout extends Marionette.Layout
template: Handlebars.compile $("#main_layout_hb").html()
regions:
header : "#header"
options : "#options"
footer : "#footer"
class MainRegion extends Marionette.Region
el:"#main_wrap"
class App extends Marionette.Application
main_region : new MainRegion
main_layout : new MainLayout
onStart: =>
#main_region.show(#main_layout)
# start the backbone history for URL routing
if Backbone.history
Backbone.history.start()
app = new App
app.start()
I'm trying to follow the example on this page https://github.com/marionettejs/backbone.marionette/wiki/The-relationship-between-regions-and-layouts
But when I run the code, I don't get the template "#main_layout_hb" inserted into the region. What's going on there?
You should create your App's region using the addRegions method:
App.addRegions
main_region: "#main_wrap"

Resources