I have the following class that extends Backbone.View, I want all my backbone views to inherit from this class:
class BaseView
constructor: (options) ->
#bindings = []
Backbone.View.apply(#, [options])
_.extend(BaseView.prototype, Backbone.View.prototype, {
#etc. tec.
BaseView.extend = Backbone.View.extend
I can then extend my own view like this:
class BusinessUnitsView extends BaseView
initialize: (options) ->
This all works fine if they are in the same file but if I separate BaseView into a different file, I get an error message:
BaseView is undefined
How can I keep the BaseView in a different file and use it to extend my custom views?
Put this under BaseView.extend = Backbone.View.extend
#.BaseView = BaseView
it makes your BaseView global accessible
I always declare my classes like this and it works great
class BaseView extends Backbone.View
#.BaseView = BaseView
Related
Basically I have a ViewMaster with many many Functions that gets somewhere in a wrapper => components executed
Now I want to have a different but mostly the same View that needs some extra Functions. Now 2 states are changing its type from
interface ViewState {
something:something
...
}
to
interface NewViewState extends ViewState {
change:change
}
But how am I able to do this.
My ViewMaster looks like this
class ViewMaster extends React.Component<ViewProps,ViewState>{}
and my new View
class ViewNew extends ViewMaster
But how am I able to set a new ViewState generic?
EDIT: Thinking about it, I can simply change the interface ViewState
to
interface ViewState {
change:change|something
}
But still It would be intresting to know
There are a number of ways you can do this. Given that your base component is a React Component and it already has parameterization I would do something like this:
class ViewMaster<P = ViewProps, S = ViewState> extends React.Component<P, S>{}
and then
class ViewNew extends ViewMaster<ViewProps, NewViewState>{}
I'm trying to create a rich data model for an AngularJS application and I would like for my model to inherit from Array<BaseModel>. I haven't found a way to do this (with confidence) yet.
In pseudocode this would be something like:
// NOT REAL CODE. DOES NOT WORK
class BaseModel {}
class Person extends BaseModel {}
class People extends Array<Person> {
constructor(private promise:Promise) { }
$unwrap(promise) {
promise.then((response) => {
response.data.map((person) => {
this.push(new Person(person));
});
});
}
static $load() {
/* do some ajaxy thing and unwrap the promise right onto the
the new instance of this rich model */
return new People(promise);
}
}
The reason I would like something like this is that now I can bind this model directly to my view and get updates on the fly.
Any thoughts on extending from Array?
At this point it time it is not possible to inherit from Array in TypeScript. It is best to unwrap into a public array field and use this field to bind to the UI. It resolves into the same functionality and remove the necessity of inheriting from Array.
I'm writing a Backbone program in Typescript, in which I am not able to initialize any events. Here's a test class that I've created to fix the problem. The function start() is not being called when the div is clicked on.
class TestView extends Backbone.View{
events = {
"click #testDiv" : "start"
}
start(){
console.log("Clicked");
}
constructor(options?){
super(options);
}
render(){
$root.html(getNewDiv("testDiv"));
$("#testDiv").css("height", 100).css("width", 100).css("background-color", "green");
console.log("Rendered");
return this;
}
}
function getNewDiv(id:string) {
return "<div id = \"" + id + "\"></div>"
}
new TestView().render();
Here's the console output:
Rendered
Here's the backbone typescript definition that I'm using:
https://github.com/borisyankov/DefinitelyTyped/blob/master/backbone/backbone.d.ts
Here's the CDN location for backboneJS
Minified : http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone-min.js
Non-Minified : http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone.js
I'm concerned if my syntax is right or this has something to do with the Typescript definition of Backbone.
UPDATE
The answer shown by Kevin Peel below is throwing an error, because in the Typescript definition file, "events" is defined as a function ( eg. events()). If I just create an "events" function, I get the error - "Uncaught TypeError: Object [object Object] has no method 'off'". If I use the getter method (eg. get events(){}), then nothing really happens on actually firing the event.
Using delegate Events
I tried to use the delegateEvents() function in Backbone.View which creates an error:
constructor(options:any, question:Question, div:JQuery) {
this.delegateEvents({
"click" : "clicked"
});
}
Error:
Uncaught TypeError: Object [object Object] has no method 'off' backbone.js:1082
h.extend.undelegateEvents backbone.js:1082
h.extend.delegateEvents backbone.js:1059
The problem is with where TypeScript defines the events. When you define events like this:
class TestView extends Backbone.View {
events = {
"click #testDiv": "start"
}
// ...
}
What TypeScript does is attaches events as a property after initializing the instance. So when Backbone is initializing the view, events haven't yet been attached, so Backbone isn't able to bind them.
Unfortunately, there doesn't seem to be a nice way to get TypeScript to assign events to the prototype, so you need to hack around it in some way.
The absolute easiest way is by setting the events on the prototype yourself:
class TestView extends Backbone.View {
// Get rid of the events declaration in here
// ...
}
TestView.prototype.events = {
"click #testDiv": "start"
}
A second possible way to get around the issue is using the getter functionality of TypeScript as suggested in this StackOverflow answer.
Finally, a third way would be to bind your events each time you render. This is another easy way to get around the TypeScript problem, but it might not be the best solution if the view gets rendered many times.
class TestView extends Backbone.View{
events = {
"click #testDiv" : "start"
}
// ...
render(){
$root.html(getNewDiv("testDiv"));
// Here is where you'll bind the events using Backbone's delegateEvents
this.delegateEvents();
$("#testDiv").css("height", 100).css("width", 100).css("background-color", "green");
console.log("Rendered");
return this;
}
}
// ...
new TestView().render();
I know is an old question but there is now another possibility, using es7 decorators, similar to what angular2 does:
#component({
events: {
"click #testDiv" : "start"
}
})
class TestView extends Backbone.View{
start(){
console.log("Clicked");
}
render(){
// ...
}
}
Decorator file
export function component(definition: any) {
return function (constructor: any) {
Object.assign(constructor.prototype, definition)
}
}
This way, all properties defined in the component decorator will be attached to the class prototype and will be available at instantiation time.
Another option besides using a class/constructor decorator could be to use a method decorator on the preinitialize method if you wish to have all the code inside the class braces like this:
class TestView extends Backbone.View {
#component({
events: {
"click #testDiv" : "start"
}
})
preinitialize(){}
start(){
console.log("Clicked");
}
render(){
// ...
}
}
Decorator file
export function component(definition: any) {
return function (target: Object, methodName: string, descriptor: TypedPropertyDescriptor<Function>) {
Object.assign(target, definition)
}
}
I have a Marionette.ItemView that uses a CSS class to style new items differently:
class Happenator.Views.Option extends Backbone.Marionette.ItemView
tagName: 'li'
className: =>
return 'new' if #model.isNew()
initialize: ->
#bindTo #model, "change", -> #render()
When the model is saved and updated, everything refreshes but the 'new' class remains on the 'li'. Is there a good way to update the enclosing tags' class on updates?
Yes, the 'new' class remains on the 'li', because in fact Backbone uses the className property only right before an initialize method call. Take a look at this answer for more explanations.
But why don't use jQuery .toggleClass or .removeClass? Something like
render: =>
#$el.html(#template(#model.toJSON()))
unless #model.isNew()
#$el.removeClass('new')
http://jsfiddle.net/GX8WJ/21/
I have the following backbone view:
class Observation extends Backbone.Model
class Observations extends Backbone.Collection
model: Observation
constructor: ->
#url = _observationsUrl
class ObservationsView extends Backbone.View
el: $('#observations')
initialize: ->
_.bindAll #
#model.bind 'changed', #render
#model.view = #
that = #
#model.fetch {
success: ->
alert('success')
that.model.trigger 'changed'
}
render: =>
alert('rendering baby')
class ObservationsController extends Backbone.Controller
initialize: ->
observations = new Observations()
observationsView = new ObservationsView(model: observations)
I am binding the model's changed event to the render method of the ObservationsView. The model is a backbone collection.
The fetch is working successfully but the changed event is not being fired. I am trying the manual trigger out of desperation.
Can anyone see what I am doing wrong?
The event isn't called 'changed'. The event triggered after the model's collection has been refreshed from the server is 'refresh'.
The 'change' event is actually more complicated. It's an event on a model that's triggered whenever you call .set(), and it always includes the attribute, so you'd write things like:
this.model.bind('change:username', _.bind(this.update_username_display, this))
As always, the backbone.js source code is eminently readable.