npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ribcage-view

v3.0.3

Published

A simple base Backbone view class that adds subviews, rendering, and initialization.

Downloads

199

Readme

ribcage-view

A simple base Backbone view class that adds subviews, rendering, and initialization.

Install

Installing via npm is easy:

npm install ribcage-view

Ribcage requires you to use browserify (or some other way to get require on the front-end).

Usage

Simple example

var View = require('ribcage-view')

/*
 * A view that doesn't do anything but render a template
 *
 * - a template is just a function that takes an object
 *   and returns a string to be rendered.
 *
 */
var templateView = new View({
  template: function(id){
    return '<div>' + id '</div>'
  }
})

Full example

// Extending a ribcage-view
var Base = require('ribcage-view')
  , _ = require('lodash')
  // it's not required, but using a state model is _highly_ recommended.
  , State = require('ampersand-state').extend({
    extraProperties: 'reject'
  })

var MyView = Base.extend({

  template: require('./template.html.hbs')

, className: 'myView'

, State: State.extend({
    props: {
      text: 'string'
    }
  })

, events: {
    'input input': 'onInputInput'
  }

// DOM Events
 , onInputInput: function onInputInput(e){
    this.state.text = e.target.value
   }

// Backbone Events
, bindEvents: function bindEvents(){
    // always stopListening so we don't reattach multiple listeners
    if (this.state) this.stopListening(this.state)

    // listen to state, model, etc… events
    this.listenTo(this.state, 'change:text', this.onStateChangeText)
  }

, onStateChangeText: function onStateChangeText(state, value){
    console.log(value)
  }

// Create Subviews
, createSubviewX: function createSubviewX(){
    return new SubviewX({})
  }

// Lifecycle Methods
, beforeInit: function beforeInit(options){
    this.state = new this.State(_.omit(options, ['model', 'collection']))
  }

// instantiate subviews
, afterInit: function afterInit() {
    this.subviewX = this.createSubviewX()
  }

, afterRender: function afterRender() {
    this.appendSubview(this.subviewX)
  }

, context: function context() {
    return this.state.toJSON()
  }

})

module.exports = MyView

Methods

Override with caution

These are methods that are reserved by Ribcage View. Overriding will break expected behavior.

initialize()

Sets up the view and calls the render method.

render()

Attaches the template to the DOM with all DOM and backbone events attached. Returns the view.

close([<Object> options, [<Function> callback]])

Closes out a view completely by removing it and all subviews from the DOM, destroying all listeners, and the view's DOM node.

options currently only accepts one key: keepDom which is a boolean. When set to true, it will preserve the view's DOM node. This is really only useful if removing many subviews at once that all share a parent node. Instead of removing each node, we can just remove the parent when we're done closing all the subviews.

The close happens in a requestAnimationFrame and the callback will be called when the close is complete.

// kill the subview. This removes it from the DOM, kills all event listeners, closes all subviews, and is the memory-leak free way to kill a view.
// `keepDom` is false by default. If you want to close, but leave this in the DOM (probably a bad idea), you can set to `true`
// The `keepDom` option exists for closing many views that share a parent element. You can then remove just the parent element.
this.myView.close({keepDom: false}, function myViewClosed(){
  console.log('myView has been closed')
})

closeSubviews([<Object> options, [<Function> callback]])

Closes all subviews. Takes the same options as close().

eachSubview(<Function> iterator[, <Object> context])

Iterate over each subview, performing the iterator function. context defaults to the view you're calling from.

// go through all the subviews
this.eachSubview(function eachSubview(subview) {
  // `this` is the parent view
  this.doSomething(subview.property)
})

Override at will

These methods provide defaults, but you should feel free to replace them with your own.

context()

Return an object for the template to use for its data. Defaults to the options.

beforeInit(<Object> options)

Called before anything else happens. Is passed the options from the constructor. This is a good place to instantiate a state model.

afterInit(<Object> options)

Called after all the initialization has completed. This is a good place to create subviews.

loadData(<Function> done)

If defined, will block rendering until done is called. Useful if you need to async load data from the server before anything happens.

beforeRender()

Called after loadData but before anything else in the render flow.

afterRender()

Called after the render has happened. This is a good place to put subviews into the DOM.

…
, afterRender: function afterRender(){
  this.appendSubview(this.mySubview)
}
…

bindEvents()

Called on every render. This is the place to attach backbone events to subviews. Be sure you call stopListening before listenTo so that you don't create multiple listeners for the same event.

…
, bindEvents: function bindEvents(){
  // always stopListening so we don't reattach multiple listeners
  if (this.model) this.stopListening(this.model)

  this.listenTo(this.model, 'change', this.render)
}
…

Helpers

These are methods that assist with common tasks.

proxy(<String> name, <Backbone.View> view)

Listen to an event from another view (probably a subview), and trigger the same event. This is useful if you want to pass an event up the chain of subviews.

appendSubview(<Backbone.View> view[, <jQuery el> el])

Appends the view to the view's DOM. Optionally, you can pass a specific DOM node to append to.

prependSubview(<Backbone.View> view[, <jQuery el> el])

Just like appendSubview, only it prepends.

appendSubviews(<Array of Backbone.View> views[, <jQuery el> el[, <Function> callback]])

Append an array of views. You can optionally pass in the el to append into.

This is an async function that is has better performance than calling appendSubview many times because it creates a documentFragment before appending to the DOM, and uses requestAnimationFrame.

The third argument is an optional callback that is called when the views are in the DOM.

// append many subviews at once
// e.g. if you want to append a sub view for all models in a collection
var collectionSubviews = this.collection.map(function(model){
  return new MyView({model: model})
})
// only the first argument is required
this.appendSubviews(collectionSubviews, this.$('.collection'), function(views){
  // views are rendered after a requestAnimationFrame
  console.log(assert.deepEqual(views, collectionSubviews))
})

batchAppendSubviews(<Array of Backbone.View> views[, <jQuery el> el], <Int> batchCount[, <Function> batchCallback, [<Function> callback]])

This is like appendSubviews, but it requires the third argument be a Number. It allows you to append a set amount of views per animationFrame which might be necessary for performance reasons.

batchAppendSubview takes two callbacks. The first is called on every batch append, the second is called when all views have been appended.

// if your subviews take time to render and slow down the DOM
// will render 2 subviews at a time.
this.batchAppendSubviews(collectionSubviews
  , this.$('#place')
  , 2
  , function onPortionAppended(){
    console.log('2 more subviews appended')
  }
  , function onBatchAppended(){
    console.log('all subviews appended')
  }
)

detachSubview(<Backbone.View> view)

Remove a view from the DOM, but keep it's node around in memory. This is useful if you want to move it to a different node.

closeSubviewsByModel(<Backbone.Model> model)

Finds all subviews that have the model set as their model and closes them.

this.listenTo(this.collection, 'remove', this.closeSubviewsByModel)

detachSubviewByModel(<Backbone.Model> model)

Like closeSubviewsByModel, but only detaches.

Gotchas

  1. Remember to call View.prototype.initialize.apply(this, arguments) if you are override initialize. This fixes the loadData is not defined error. Alternatively, override afterInit and beforeInit instead.
  2. Subviews are closed when their parent is rendered, and will lose their events unless you call .delegateEvents() on them in the parent's afterRender. See #5.

Contributing

Developing

Run this command to run tests at http://localhost:9999.

grunt dev

Testing

Tests can be run on Saucelabs.

# Run once to set up login info
$ export SAUCE_USERNAME=YOUR-SAUCE-USERNAME
$ export SAUCE_ACCESS_KEY=YOUR-SAUCE-API-KEY

# Run to test on sauce
$ grunt test