Backbone basic app, is this how it should be done? - javascript

Hope you can have a quick look at what I'm doing here. Essentially, am I doing it right?
Live demo of it here too: http://littlejim.co.uk/code/backbone/messing-around/
I just wanted to get a solid understanding in Backbone before I go too wild. So this is a simple demonstration of creating a collection from a JSON object, passing it to a view and handling simple events. But am I approaching this right? What can I do that's better?
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Showing a simple view with events</title>
<script type="text/javascript" src="../../media/scripts/jquery-1.5.1.min.js"></script>
<script type="text/javascript" src="../../media/scripts/underscore-min.js"></script>
<script type="text/javascript" src="../../media/scripts/backbone-min.js"></script>
<script type="text/javascript" src="application.js"></script>
</head>
<body>
<header>
<h1>Showing views from a collection and basic events</h1>
<p>The list below is made from JSON, passed to the view as a collection and has basic events</p>
</header>
<article>
</article>
</body>
</html>
Here is the JavaScript I currently have. I just need to know if I'm approaching this correctly?
window.App = {
// namespaces
Controller: {},
Model : {},
Collection : {},
View : {},
// code that starts when the app is first fired
initialize : function () {
var collection = new App.Collection.Inputs([
{title: "Item 1"},
{title: "Item 2"},
{title: "Item 3"}
]);
var view = new App.View.InputSet({collection: collection});
$('article').html(view.render().el);
}
}
/*
Collection: Inputs */
App.Collection.Inputs = Backbone.Collection.extend();
/*
View: _Input */
App.View._Input = Backbone.View.extend({
events: {
"click a": "close"
},
// called as soon as a view instance is made
initialize: function() {
// this makes the render, clear etc available at this
// if not setting this, both render() and clear() method will not have themselves in this
_.bindAll(this, "render", "close");
},
// backbone required method, which renders the UI
render: function() {
// this is using underscore templating, which can be passed context
$(this.el).html(_.template('<p><%=title%> [close]</p>', this.model.toJSON()));
return this;
},
close: function() {
// removes the UI element from the page
$(this.el).fadeOut(300);
return false; // don't want click to actually happen
}
});
/*
View: InputSet, uses _Input */
App.View.InputSet = Backbone.View.extend({
events: {
'click a': 'clear'
},
initialize: function() {
// this makes the render, clear etc available at this
// if not setting this, both render() and clear() method will not have themselves in this
_.bindAll(this, "render");
},
// backbone required method, which renders the UI
render: function() {
var that = this;
views = this.collection.map(function(model) {
var view = new App.View._Input({model: model});
$(that.el).append(view.render().el);
return view;
});
$(that.el).append('[clear]');
return this;
},
clear: function() {
$(this.el).find('p').fadeOut(300);
}
});
// wait for the dom to load
$(document).ready(function() {
// this isn't backbone. this is running our earlier defined initialize in App
App.initialize();
});

This looks fine to me. However, I found that things can get tricky once you start doing non-trivial stuff: complex views, nested collections etc.
One thing that could be done differently is that instead of generating input views using collection.map you could bind the collection's add event to a function that generates an _Input view for that item in the collection instead. So you'd have something like this in your InputSet view:
initialize: function() {
_.bindAll(this, "addInput", "removeInput");
this.collection.bind("add", this.addInput);
this.collection.bind("remove", this.removeInput);
}
addInput: function(model) {
var view = new App.View._Input({model: model});
$(this.el).append(view.render().el);
}

I looks good to me - really the only thing I would suggest is that you bind the collection's 'change' event to _Input.render that way changes to your collection automatically re-render the view:
// called as soon as a view instance is made
initialize: function() {
_.bindAll(this, "render", "close");
this.collection.bind('change', this.render);
},
Other than that I think it looks good!

Related

Backbone JS Button to open a new view, save values in form

Im new to backbone and I'm looking to a very simple 2 view configuration page usig backbone.
I have the following code;
define(
["backbone","...","..."],
function(Backbone, ... , ... ) {
var PopupView = Backbone.View.extend({
initialize: function initialize() {
Backbone.View.prototype.initialize.apply(this,arguments);
},
events: {
"click .save_conf_button": "save_conf",
},
render: function() {
this.el.innerHTML = this.get_popup_template();
return this;
},
save:conf: function save_conf() {
//get the field values from popup_template
//var items = jquery(....);
});
var ExampleView = Backbone.View.extend({
//Starting view
initialize: function initialize() {
Backbone.View.prototype.initialize.apply(this, arguments);
},
events: {
"click .setup_button": "trigger_setup", //Triggers final setup
"click .create_conf_button": "trigger_popup_setup", //This is the conf popup
},
render: function() {
this.el.innerHTML = this.get_start_html();
return this;
},
trigger_popup_setup: function trigger_popup_setup() {
console.log("Pop up");
//this.el.innerHTML = this.get_popup_template();
PopupView.render();
...
},
}); //End of exampleView
return ExampleView;
} // end of require asynch
); // end of require
E.g. The ExampleView is the starting view with a couple of fields and 2 buttons; create popup and save. Upon pressing the create_conf_button I want to render the popup view, however this does not seem to work as I expected. (Uncaught TypeError: PopupView.render is not a function)
I'm not sure how to proceed and additionally what the "best practice" is for generating these types of dialogs?
Additionally, keeping the values filled in on the previous page after returning from the popupview would be preferential.
Thanks for any help
try
new PopupView.render()
you have to create an instance to call the methods this way
#ashish is correct, you have to instantiate an instance of the PopupView before calling its render method. Currently, you have defined a blueprint for a view called PopupView, which will act as a constructor for newly created PopupView view instances. In order to use this defined view I would suggest storing it in ExampleView's render or initialize method:
// Example View's initialize method
initialize: function initialize() {
this.popUpView = new PopupView();
Backbone.View.prototype.initialize.apply(this, arguments);
},
then referencing it in your trigger_popup_setup function as follows:
trigger_popup_setup: function trigger_popup_setup() {
console.log("Pop up");
//this.el.innerHTML = this.get_popup_template();
this.popUpView.render();
...
},
As for storing state Backbone models are used for that :)
In general to nest subviews within a master view in Backbone you can do the following:
initialize : function () {
//...
},
render : function () {
this.$el.empty();
this.innerView1 = new Subview({options});
this.innerView2 = new Subview({options});
this.$('.inner-view-container')
.append(this.innerView1.el)
.append(this.innerView2.el);
}
In this example the master view is creating instances of it's subviews within its render method and attaching them to a corresponding DOM element.

Backbone.js: Populating my collection and then appending it to the page

I am working in backbone.js. In the following code I am making a call to the Nutritionix API in order to populate my collection with the JSON response. I am having trouble populating my collection and appending the result as a list. I am doing this in order to test if my collection has been properly populated and in order to test that it will append to the page. However when I test the code out in the browser I don't see the field[brand_name] attribute appended to the page. Is my collection properly populated? How can I see the aformentioned attribute appended to the page? What is wrong with my code?
Here is my Javascript:
$(function(){
var SearchList = Backbone.Collection.extend({
url: "https://api.nutritionix.com/v1_1/search/taco?results=0%3A20&cal_min=0&cal_max=50000&fields=item_name%2Cbrand_name%2Citem_id%2Cbrand_id&appId=26952a04&appKey=78e2b31849de080049d26dc6cf4f338c",
initialize: function(){
this.bind("reset", function(model, options){
console.log("Inside event");
console.log(model);
});
}
});
var terms = new SearchList();
terms.fetch({
success: function(response,xhr) {
console.log("Inside success");
console.log(response.toJSON());
},
ERROR: function (errorResponse) {
console.log(errorResponse)
}
});
// The main view of the application
var App = Backbone.View.extend({
// Base the view on an existing element
el: $('.container'),
initialize: function(){
this.listenTo(this.model, 'sync', this.render);
// Cache these selectors
// this.total = $('#total span');
this.list = $('#listing');
},
render: function(){
// Calculate the total order amount by agregating
// the prices of only the checked elements
terms.each(function(term){
this.list.append("<li>"+ term.get('field[brand_name]')+"</li>");
}, this);
}
});
});
Here is my HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>Interactive Food Guide</h1>
<div>
<input type="text" id="searchBox"> <br/><br/>
</div>
<ul id="listing"></ul>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Backbone and Underscore -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.2.1/backbone-min.js"></script>
<!-- apps functionality -->
<script src="js/app.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
</body>
</html>
I can see some errors in the code:
JSON returned by url is an object, and what you should charge in the collection is the array "hits" that is inside the object. The logic of this process is defined in the method "parse" the collection.
The collection was declared out of view. When indicated in view to listen to your collection, you will have problems because the fetch method call before the view can be instantiated, so the view does not realize when the fetch is executed
Here is your code with comments.
$(function(){
var SearchList = Backbone.Collection.extend({
url: "https://api.nutritionix.com/v1_1/search/taco?results=0%3A20&cal_min=0&cal_max=50000&fields=item_name%2Cbrand_name%2Citem_id%2Cbrand_id&appId=26952a04&appKey=78e2b31849de080049d26dc6cf4f338c",
initialize: function(){
},
//** 1. Function "parse" is a Backbone function to parse the response properly
parse:function(response){
//** return the array inside response, when returning the array
//** we left to Backone populate this collection
return response.hits;
}
});
// The main view of the application
var App = Backbone.View.extend({
// Base the view on an existing element
el: $('.container'),
initialize: function(){
//** 2. the view must listen to an object inside in the view
//** so we create a new instance of SearchList and save it into model var of the view
this.model = new SearchList();
this.model.fetch();
this.listenTo(this.model, 'sync', this.render);
// Cache these selectors
// this.total = $('#total span');
this.list = $('#listing');
},
render: function(){
//** 2. Continue
var terms = this.model;
// Calculate the total order amount by agregating
// the prices of only the checked elements
terms.each(function(term){
this.list.append("<li>"+ term.get('fields')["brand_name"]+"</li>");
}, this);
}
});
//** Create an instance of the view to start the program
var foo = new App();
});
Regards
I think the main issue here is that you forgot to instantiate your app:
new App();
Secondly you need to refer to your data with the correct structure:
term.get('hits')
As term is the model, which contains an array of hits
Lastly, you need your collection in your view, and listen for the sync on your views collection:
this.listenTo(this.collection, 'sync', this.render);
I updated your app.js like so:
$(function(){
var SearchList = Backbone.Collection.extend({
url: "https://api.nutritionix.com/v1_1/search/taco?results=0%3A20&cal_min=0&cal_max=50000&fields=item_name%2Cbrand_name%2Citem_id%2Cbrand_id&appId=26952a04&appKey=78e2b31849de080049d26dc6cf4f338c",
initialize: function(){
this.bind("reset", function(model, options){
console.log("Inside event");
console.log(model);
});
}
});
// The main view of the application
var App = Backbone.View.extend({
// Base the view on an existing element
el: $('.container'),
initialize: function () {
this.collection = new SearchList();
this.collection.fetch({
success: function (response, xhr) {
console.log("Inside success");
console.log(response.toJSON());
},
ERROR: function (errorResponse) {
console.log(errorResponse)
}
});
this.listenTo(this.collection, 'sync', this.render);
// Cache these selectors
// this.total = $('#total span');
this.list = $('#listing');
},
render: function(){
var context = this;
this.collection.each(function (term) {
_.each(term.get('hits'), function (item) {
context.list.append("<li>" + item.fields.brand_name + "</li>");
});
}, this);
}
});
new App();
});
The correct way is not to use var context = this; but an element on your view. I just wanted to point you in the right direction :-)

Backbone JS view render not displaying [duplicate]

This question already has an answer here:
Unable to display Todo Collection on the page
(1 answer)
Closed 8 years ago.
In the below code, unable to render 'TodoList'. Seems like fetching taking time and so displaying '0' and <div id=​"demo">​</div>​ before only.
and Iam not sure why '3' and 'Descriptions' got displayed later. All I need is to display 'Descriptions List' in the page. Iam able to get data from server but somehow not able to display as soon as the data arrived. Please tell me what changes need to do in the below code?
<html>
<head>
<link rel="stylesheet"
href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/css/bootstrap.min.css">
</head>
<body>
<div id="demo"></div>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js"></script>
<script type="text/javascript">
var TodoItem = Backbone.Model.extend({
urlRoot: 'api',
})
var TodoCollection = Backbone.Collection.extend({
model: TodoItem,
url: 'api/todos'
})
var TodoView = Backbone.View.extend({
template: _.template('<h3> ' +'<input type=checkbox ' +'<% if(status === "complete") print("checked") %>/>' +' <%= description %></h3>'),
render: function(){
this.$el.html(this.template(this.model.toJSON()))
}
})
var TodoListView = Backbone.View.extend({
initialize: function(){
this.listenTo(this.collection,'reset',this.render)
this.collection.fetch({reset:true})
},
render: function(){
console.log(this.collection.length)
this.collection.forEach(this.addOne,this)
},
addOne: function(todoItem){
console.log(todoItem.get('description'))
var todoView = new TodoView({model: todoItem})
this.$el.append(todoView.render())
}
})
var todoItem = new TodoItem()
var todoList = new TodoCollection()
var todoListView = new TodoListView({el: '#demo', collection: todoList})
todoListView.render()
console.log(todoListView.el)
</script>
</body>
</html>
Here is the CONSOLE output Iam getting:
0
<div id=​"demo">​</div>​
3
pick up cookies
Milk
Cookies
For starters you might want to take out the {reset: true} from your fetch.
A fetch wil automatically clear the model/collection anyway.
Please also use semicolons at the end of your command, not using them will let the browser interpret where the semicolon should be. This takes time and is error prone (the browser might just place it where you didn't think it would).
if this does not work you might want to do add the fetch into the render doing this:
render: function(){
var that = this;
this.collection.fetch().done(function(data) {
console.log(that.collection.length);
that.collection.forEach(that.addOne,that);
});
},
What also might work, but you need to test this, I personally always use the one above:
render: function(){
this.collection.fetch().done(function(data) {
console.log(this.collection.length);
this.collection.forEach(this.addOne,this);
}, this);
},
and Iam not sure why '3' and 'Descriptions' got displayed later - Because it the result of a async Ajax request.
now, try to change your code (watch comment):
var TodoView = Backbone.View.extend({
template: _.template('<h3> ' +'<input type=checkbox ' +'<% if(status === "complete") print("checked") %>/>' +' <%= description %></h3>'),
clearItem : function(){
this.$el.find("h3").remove();
},
render: function(){
//all DOM manipulation in view
this.$el.append(this.template(this.model.attributes));
return this;
}
})
var TodoListView = Backbone.View.extend({
initialize: function(){
// split "reset" event and "add" event
this.listenTo(this.collection,'reset',this.removeAll);
this.listenTo(this.collection,'add',this.addOne);
this.collection.fetch({reset:true});
},
removeAll : function(){
//method to remove all element from view
//your problem is that this event will fire before ajax request done
console.log("reset!");
var todoView = new TodoView();
todoView.clearItem();
},
addOne: function(todoItem){
//fire when a model in the collection change (automatic after fetch result) for each model.
console.log("add ITEM:",todoItem);
var todoView = new TodoView({model: todoItem})
todoView.render();
}
});
NOTE: Remove todoListView.render() in your code.
Sorry but, my english is too bad. I do not have time to explain better. Try if my code work
EVENTS in backbone: http://backbonejs.org/#Events
FETCH in collection: http://backbonejs.org/#Collection-fetch
RENDER a view: http://backbonejs.org/#View-render

Again on Backbone Zombie Views

I am trying to understand backbone and am currently struggling with zombie views. I have read many stack overflow posts on the matter but I still cannot figure it out.
For the sake of simplicity, I set up two views (without data) that I need to switch.
What I did so far was:
creating an object
//define application object
var app = {
vent: {},
templates: {},
views: {},
routers: {},
};
//instantiate event aggregator and attach it to app
app.vent = _.extend({}, Backbone.Events);
defining two very simple templates (stored into app.templates): the first one has some dummy text and a button (with and id of 'test-begin'), the second one just dummy text
defining two views
app.views.instructions = Backbone.View.extend({
//load underscore template
template: _.template(app.templates.instructions),
//automatically called upon instantiation
initialize: function(options) {
//bind relevant fucntions to the view
_.bindAll(this, 'render', 'testBegin', 'stillAlive', 'beforeClose');
//listen to app.vent event
this.listenTo(app.vent, 'still:alive', this.stillAlive);
},
//bind events to DOM elements
events: {
'click #test-begin' : 'testBegin',
},
//render view
render: function() {
this.$el.html(this.template());
return this;
},
//begin test
testBegin: function() {
Backbone.history.navigate('begin', {trigger: true});
},
//still alive
stillAlive: function() {
console.log('I am still alive');
},
//before closing
beforeClose: function() {
//stop listening to app.vent
this.stopListening(app.vent);
},
});
//test view
app.views.test = Backbone.View.extend({
//load underscore template
template: _.template(app.templates.test),
//automatically called upon instantiation
initialize: function(options) {
//trigger still:alive and see if removed view responds to it
app.vent.trigger('still:alive');
//bind relevant fucntions to the view
_.bindAll(this, 'render');
},
//render view
render: function() {
this.$el.html(this.template());
return this;
},
});
defining a router
//base router
app.routers.baseRouter = Backbone.Router.extend({
//routes
routes: {
'': "instructions",
'begin': "beginTest"
},
//functions (belong to object controller)
instructions: function() {baseController.instructions()},
beginTest : function() {baseController.beginTest()},
});
//baseRouter controller
var baseController = {
instructions: function() {
mainApp.viewsManager.rederView(new app.views.instructions());
},
beginTest: function(options) {
mainApp.viewsManager.rederView(new app.views.test());
},
};
defining mainApp (with a view-switcher)
//define mainApplication object
mainApp = {};
//manages views switching
mainApp.viewsManager = {
//rootEl
rootEl: '#test-container',
//close current view and show next one
rederView : function(view, rootEl) {
//if DOM el isn't passed, set it to the default RootEl
rootEl = rootEl || this.rootEl;
//close current view
if (this.currentView) this.currentView.close();
//store reference to next view
this.currentView = view;
//render next view
$(rootEl).html(this.currentView.render().el);
},
};
//render first view of app
mainApp.viewsManager.rederView(new app.views.instructions());
//initiate router and attach it to app
mainApp.baseRouter = new app.routers.baseRouter();
//start Backbone history
Backbone.history.start({silent: true
});
adding a close function to view via Backbone prototype
//add function to Backbone view prototype (available in all views)
Backbone.View.prototype.close = function () {
//call view beforeClose function if it is defined in the view
if (this.beforeClose) this.beforeClose();
//this.el is removed from the DOM & DOM element's events are cleaned up
this.remove();
//unbind any model and collection events that the view is bound to
this.stopListening();
//check whether view has subviews
if (this.hasOwnProperty('_subViews')) {
//loop thorugh current view's subviews
_(this._subViews).each(function(child){
//invoke subview's close method
child.close();
});
}
};
So, in order to check for zombie views, the second view triggers and event (still:alive) that the first view listen to and respond to it via a message sent to the console.log (although it really shouldn't).
The first view does listen to such a message (in the console log I read 'I am still alive) even when it has been replaced by the second view.
Can you help me? thank you very.
Long post, if you have any questions, please ask
A Zombie View is just a view that is not in the DOM, but listens to and reacts to events -- sometimes this behavior is expected, but not typically.
If the DOM Event handlers for the view are not properly removed, the view and it's in-memory HTML fragments will not be garbage collected. If the Backbone.Event handlers are not unbound properly, you could have all sorts of bad behavior... such as a bunch of "Zombie" view triggering AJAX requests on models. This problem was very common on older versions of Backbone prior to stopListening and listenTo especially if you shared models between views.
In your code, you don't have a Zombie View, because you are properly closing your views.
You can see the console.log because you are initializing the second view (and triggering the event still:alive) before you close the first view.
To switch views, you are calling:
mainApp.viewsManager.rederView(new app.views.test());
Calling new app.views.test() initializes the second view which triggers the event that the first listens to.
If you update your code to the following, you won't see the console.log anymore.
//baseRouter controller
var baseController = {
instructions: function() {
mainApp.viewsManager.rederView(app.views.instructions);
},
beginTest: function(options) {
mainApp.viewsManager.rederView(app.views.test);
},
};
And update rederView
rederView : function(ViewClass, rootEl) {
//if DOM el isn't passed, set it to the default RootEl
rootEl = rootEl || this.rootEl;
//close current view
if (this.currentView) this.currentView.close();
//store reference to next view
this.currentView = new ViewClass();
//render next view
$(rootEl).html(this.currentView.render().el);
},
If you remove this line from your close method, you will have a zombie view and should see the console.log.
//unbind any model and collection events that the view is bound to
this.stopListening();
Zombie View Example
In the following code, I am creating 100 views, but only displaying 1 in the DOM. Every view contains the same model and listens to it's change event. When the view's <button> element is clicked, it updates the model which causes every view's model change handler to be executed, calling fetch 100 times... 100 AJAX requests!
The view's change handlers are called 100 times, because the view close method does not call this.stopListening(), so even when the views are removed from the page, they all still listen to the model's events. Once you click the button, the model is changed, and all of the zombie views respond, even though they're not on the page.
var TestView = Backbone.View.extend({
tagName: 'h1',
initialize: function(options) {
this.i = options.i;
this.listenTo(options.model, 'change', function(model) {
model.fetch();
});
},
events: {
'click button': function() {
this.model.set("show_zombies", Date.now());
}
},
render: function() {
this.$el.append("<button>Click To Test for Zombies!</button>");
return this;
},
close: function() {
this.$el.empty(); // empty view html
// this.$el.off(); // // Whoops! Forgot to unbind Event listeners! (this view won't get garbage collected)
// this.stopListening() // Whoops! Forgot to unbind Backbone.Event listeners.
}
});
var model = new (Backbone.Model.extend({
fetch: function() {
document.body.innerHTML += "MODEL.FETCH CALLED<br />"
}
}));
var v;
for (var i = 1; i < 101; i++) {
if (v) v.close();
v = new TestView({
'i': i,
'model': model
}).render();
$('body').html(v.el);
}
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone.js"></script>

How do I wait for Sproutcore 2.0 to have loaded all templates?

In my app, the <body> tag contains just a single <script type="text/x-handlebars> tag which contains all my views. Sproutcore 2.0 nicely adds a jQuery on-document-ready handler that parses those templates and renders them back into the DOM.
I'd like to call a function on one of the views as soon as it's rendered. The problem is that the re-insertion happens asynchronously, so I don't know when the view is available.
Example
Page
<body>
<script type="text/x-handlebars">
...
{{view "MyApp.TweetInputView"}}
...
</script>
</body>
View:
MyApp.TweetInputView = SC.View.extend({
init: function() {
// act like a singleton
MyApp.TweetInputView.instance = this;
return this._super();
},
focus: function() {
...
this.$().focus();
}
});
Initializer
// if the URL is /tweets/new, focus on the tweet input view
$(function() {
if (window.location.pathname === '/tweets/new') {
// doesn't work, because the view hasn't been created yet:
MyApp.TweetInputView.instance.focus();
}
});
I've also tried SC.run.schedule('render', function() { MyApp.TweetInputView.instance.focus(); }, 'call'); in the hopes that Sproutcore would run that after all the view rendering and insertion, but that does not seem to be the case.
Try this:
MyApp.TweetInputView = SC.View.extend({
didInsertElement: function() {
console.log("I've been rendered!");
}
});

Categories