renderTpl() intricacies - extjs

The Ext.Component "renderTpl" property default value is:
'{%this.renderContent(out,values)%}'
Where can I find a detailed explanation about that mechanism?
Where is that "renderContent" method defined? Can't find any reference in the documentation.
It seems that certain methods are dynamically created:
The renderTpl contains calls to render things like docked items,
container items and raw markup (such as the html or tpl config
properties). These calls are to methods added to the Ext.XTemplate
instance by #setupRenderTpl. The #setupRenderTpl method adds methods
such as renderItems, renderContent, etc. to the template. These are
directed to "doRenderItems", "doRenderContent" etc..
That means that setupRenderTpl and renderContent are virtual methods added on the fly?
Where can I find more info. about this?
Thanks.

Related

Data-binding in Widgets

I am trying to data-bind a app/Models/mymodel.js in app/widgets/mywidget/widget.xml
<Collection src="mymodel" instance="true" id="aModel" />
I get the following error:
[ERROR] : Script Error Couldn't find module: alloy/widgets/mywidget/models/mymodel for architecture: x86_64
Not specifying WPATH in widget/ctrl.js and widget/style.tss resulting in Alloy.create* methods pick up from app/ controller or models.
Is there a way to specify to use app/Model in widget/xml
Widgets are independent. They're supposed to be shared across apps. So having a dependency on the app, or a specific model, is not the way it is supposed to be and it is designed so it won't work for this reason.
If you've written the widget yourself specifically for this app remove it, and move code to a separate controller.
If you want to share the widget across apps and want to use a collection inside it, make an exported function and provide the collection to it.
In your widget create a model file with a generic name. Include that collection inside your widget.xml. Then in your widget.js create a method to import the collection
exports.setCollection = function(collection){
$.myCollection.reset(collection.models);
}
Then in your controller including the widget:
$.myWidget.setCollection($.myOtherCollection);
This will set all models of the imported collection to the widget collection. Have an ID attribute that doesn't match? Do some converting in the setCollection method so ID does match. That way it is reusable across apps.
For example, your ID attribute is ObjectId, then you this:
exports.setCollection = function(collection, IdAttribute){
_.each(collection, function(model){
model.set({id: model.get(IdAttribute)}, {silent: true});
});
$.myCollection.reset(collection.models);
}
Then in your controller including the widget:
$.myWidget.setCollection($.myOtherCollection,'ObjectId');
Then you've transformed your collection and all should work

ExtJS ref to panel element with specific title

I am working on a project in ExtJS 4.2 written in the MVC pattern. I need a reference to a specific item inside MyViewport (extended from the class Ext.container.Viewport). The item which needs to be referenced from within the controller has the Class MyPanel (extended from "Ext.Panel"). Problem is there are several items with the same class, so simply doing a standart ExtJs-component-query like,
//inside myController.js
refs: [
...
{ref: 'specificItem', selector: 'MyViewport_alias > myPanel_alias'},
...
]
wont get me a reference to the item. Thats why i thought of retrieving the reference by something like this, since the items using MyPanel-class have a property title:
//inside myController.js
refs: [
...
{ref: 'specificItem',
selector: 'MyViewport_alias > myPanel_alias > title="title of specific item"'},
...
]
But i coulnd't find any examples on retrieving items as references by using their properties as parts of the component query other than this.
Has someone experience with this kind of problem?
Component queries in ExtJS are very similar to CSS query selectors. You could find a component by a specific property with syntax similar to: "... > [title=My Component Title]" - that said, using the "title" sounds like really bad practice.
At worst, as a visible part of the user-interface it's very sensitive to change - easily breaking your application and at best it immediately limits your application's language-support and configurability.
Ideally you should be utilising the itemId property as a more robust way of referencing components.
» fiddle
I hadn't noticed that 4.2 didn't support attribute selectors - the component query functionality seems to have always drawn inspiration from CSS though, so unfortunately if it's only a recent development it doesn't look like there's any way to do what you want using this method.
You'd have to manually fetch the component and/or create your own reference. You can select by xtype / alias in 4.2 and then apply a filter to the result, for example:
Ext.Array.filter(Ext.ComponentQuery.query('panel'), function(x){
return !!x.title.match('Sub Panel 2');
}).shift();
( Obviously no use in a controller's refs )
» fiddle
... this is however ugly - all the more reason to use itemId's properly. There was already an example of this in action in the first fiddle. All you need to do is assign an alphanumeric string (no spaces) to the property - these don't strictly need to be unique but it's generally preferable. Then in your selector simply prefix a hash # in front of the string which indicates to the engine that you are looking for a component with a specific ID.
itemId selectors definitely work in 4.2 so without seeing your code I can only speculate as to what the problem is. In your post you are using > which narrows the query to direct descendants only. Are you absolutely sure that the component you are looking for is a child of myPanel_alias and not wrapped up in another container? i.e.
"myPanel_alias #myItemId" <-- try this
"myPanel_alias > #myItemId" <-- instead of this

Get rid of surrounding elements in Backbone.Marionette

I have the following view:
return Marionette.ItemView.extend({
el: '<section>',
template: JST['app/scripts/templates/grid.ejs'],
that is called like this:
// a Layout
regions: {
grid: '#grid',
detail: '#detail'
},
onShow: function () {
var detailModel = new DetailModel();
var g = new GridView(detailModel);
this.grid.show(g);
}
The question is: How do I get rid of the surrounding section element ? I tried to omit the el property but that gives me the following strange looking div:
<div productname>
Regards Roger
The surrounding element is required for backbone to work. It is essentially a container/placeholder for your view to sit in, whether its contents have been rendered or not.
If you really insist on not having the container then I would consider resorting to the following:
https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.region.md#set-how-views-el-is-attached
Marionette.Region.prototype.open = function(view){
this.$el.empty().append(view.$el.children());
}
I say 'resorting' because, in my opinion, this is not how Backbone is supposed to be used and may have side-effects. (im not quite sure what will happen when the view in that region tries to re render; what will it's el element be pointing to?)
To expand on Scott's answer, it's probably a very bad idea to try and force the removal of the surronding view tags.
All Backbone views are contained within an DOM element. Given this fact, you have 2 main options:
have Backbone put your view into the default div element
specify which element you want Backbone to wrap your view with, using the el or tagName attributes
If the "extra" tags are creating issues (e.g. you need to generate a specific HTML set for use with a plugin), then you're not defining the wrapping element properly. For more on the subject, take a look at this blog post of mine: http://davidsulc.com/blog/2013/02/03/tutorial-nested-views-using-backbone-marionettes-compositeview/
Edit based on jsFiddle: the reason for your strange behavior is that you were passing a model instance to the initialize function. This is then interpreted as attributes for the view and get set as HTML attributes.
The correct way to provide a model instance to a view is :
new App.FooterView({
model: new App.Model()
})
In other words, you provide a javascript object to the view, with a model property. If you want to learn Marionette basics quickly, check out the free preview to my book: http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf (You'll find how to instantiate a view with a model on pages 15-21)

Backbone view based on model from collection, how to update view?

I am looking for a bit of direction I am still fairly new to Backbone and am currently creating a test application to learn more.
My problem is this, I am populating a backbone view with a underscore template. I load a collection of models, then I find the model I need and populate these values into the template. There can be many pages based on the template so I have a dynamic route that accepts an id.
My problem is I want to add a next feature, that would change the current page and reload the template with the new model.
I have tried a crude method along the lines of :
Backbone.history.navigate(newLocation)
However this did'nt work, please note newLocation is actually populated with the route and the id I want to navigate to.
I will add some code from my view below, I won't include the full code however if it is needed please ask.
Any help or a push in the right direction would be great.
Thanks in advance
You need to use your router object's navigate method rather than than history's class method, and you need to pass it the option `{trigger: true} in order to invoke the corresponding route function.

Backbone Marionette modules as Widgets similar to Twitter Flight

I'm reading up in choosing the correct client-side framework to segment/modularize my frontend code in Widgets.
Basically what I have/want is:
a complex website with multiple pagetypes, so no single-page application.
all pages are able to render a complete page WITHOUT the use of javascript. IOW: javascript is used as enrichment only.
Lots of pages have a very dynamic way in which widgets can be shown on screen. To overcome complexity at the server-side I've modularized my code into widgets (composite pattern), where each widget is responsible for it's own:
server-side controller code
server-side templating (using hogan/mustache)
routing endpoints, should it need to be called from the client
structural css (css converning the structure of the widget as opposed to the look&feel)
a server-side RegionManager ultimately decides which widgets are rendered and where they are rendered on screen. Endresults is that the RegionManager spits out the entire html (server-generated) as the composite of the rendering of all of it's widgets.
Now, some of these widgets DO have client-side logic and need rerendering on the client. Take a searchpage for instance, which needs to be able to update through ajax. (I've described this process, which uses DRY templating on client and server, here)
What I ultimately want is that, given I already use the composite pattern on the server, to extend this to the client somehow so that a Widget (1 particular logic block on the screen) contains all mentioned server-side code, plus all needed client-side code.
I hope this makes sense.
Would Marionette be suited to be used as a client side framework in this scenario? I'm asking since I'm not 100% sure if the concept of a Marionette Module is what I describe as being a Widget in above scenario. (I'm mentioning Twitter Flight in my question, since I believe this would be a fit, but it currently is so new that I'm hesitant to go with it at the moment_
I think basically what I'm asking is if anybody has some experience doing something along these lines.
I think just using Backbone.js is perfect for this type of application you are describing. You have probably already read this, but most of the backbone literature is focused around your views having associated server generated JSON models and collections, then using the View's render function to generate (on the client) the HTML UI that represents the model/collection.
However it doesn't have to be used this way. In fact there is nothing stopping you attaching views to existing elements that contain content already, which gives you all of the benefits of Backbone's modularity, events system and so on. I often use views that have no model or collection, purely because I like the conformity of style. I have also used an approach like I describe below in the cases where I have had to work with older, existing applications that have not yet got, or never will have a nice REST API, but they do provide content in HTML.
Firstly, lets assume the following HTML represents one of your widgets:
<div id="widget">
<div class="widget-title"></div>
<div class="widget-body">
<!-- assume lots more html is in here -->
Do something!
</div>
</div>
In this case, you could use backbone with a single Widget Model. This would be a very simple model, like this:
App.WidgetModel = Backbone.Model.extend({
intialize: function () {
this.url = this.options.url;
}
});
Take note of the fact the Widget receives a URL as a parameter to its constructor/initialize function. This widget model would represent many of your widgets (and of course you could adopt this general approach with more complicated models and pluck different data from the rendered HTML). So next for your views. As you probably know, normally you pass most views a model or collection when you instantiate them. However in this case, you could create the Widget model in your View's initialize Function and pass it a URL from the pre-rendered HTML as follows:
App.WidgetView = App.View.ComboboxView = Backbone.View.extend({
initialize: function () {
this.model = new App.WidgetModel({}, { url: this.$("a").attr("href") });
}
// rest of the view code
});
So instantiating the view would be something like:
new App.WidgetView({el: $("#widget")})'
By doing all of the above you can do pretty much everything else that backbone offers you and its modular and encapsulated nicely, which is what you are after.
The end result of this whole approach is:
You have rendered the Widget UI as pure HTML which (I assume) is functional without JavaScript.
You attach a View to the existing HTML.
You pass into the View as options, content by extracted (such as a URL) from the rendered HTML with jQuery.
The View is responsible for instantiating the Model passing on the relevant options the model needs (such as a URL).
This means all dynamic server side content is intially contained in the rendered HTML and your View is a modular JavaScript component that can do stuff to it, which I think is the end result you're after.
So you mentioned that you would like to have AJAX functionality for your widgets and that fine with this approach too. Using this approach, you can now use the standard Backbone fetch and save functions on the Widget model to get new content. In this example it is from the URL retrieved from the rendered HTML. When you get the response, you can use the view's, render function, or other finer grained functions to update the HTML on the page as required.
A few points:
The only thing to look out for is that you'll need to change the content type of the fetch and save functions to "text/html" if that's what the server is providing. For example:
this.model.fetch({
type: "POST",
contentType: "text/html"
});
Lastly, the model I have proposed is instantiated with no content. However if your ajax calls are a content type of "text/html", you may need to play around with you model so it can store this content in its attributes collection properly. See this answer for more information.

Resources