I'm using backbone js for handling my views and models but I wish to render the templates using Html.EditorFor in ASP.NET MVC. This is because my forms are dynamically created based on a C# class. I have only tried underscore for JavaScript templating but it requires markup in the value field like this <%=heading%> and that is not an option for me. I need a template engine that can map my form using the name of each form component, or if there are some other view engine that can render the same markup that works for both the server and the js template engine.
UPDATE
In my view I'm using Html.EditorFor like this:
#foreach (var type in Html.GetAvailablePageModels()) {
var content = Activator.CreateInstance(type) as IContent;
<script id="view-template-#type.Name" type="text/html">
#using (Html.BeginForm()) {
#Html.EditorFor(x => content)
<input type="submit" value="Save"/>
}
</script>
}
Then in my backbone view I'm doing something like this:
var PageModel = Backbone.Model.extend({
urlRoot: '/api/page'
});
var page = new PageModel({ id: 'articles/85' });
page.fetch();
var EditView = Backbone.View.extend({
el: $('div#main'),
initialize: function () {
this.template = _.template($('#view-template-Article').html());
this.render();
},
render: function () {
$(this.el).html(this.template(this.model.toJSON())); // <-- set the values correct in my pre rendered form
return this;
}
});
window.editView = new EditView({ model: page });
In the above code where I bind the model to the template I need to make sure that the field called heading binds to the correct form field with name="heading".
Change the way underscore templates work:
_.templateSettings = {
interpolate : /\{\{([\s\S]+?)\}\}/g
};
Now you can write HTML templates like this:
This is a message: {{message}}
Instead of the old-school <%= message %> style. This will let you generate the templates you want from your Razor views on the server. I did this on a project once and it worked out really well.
Related
So with the introduction of components and custom elements it seems a lot easier to encapsulate your logic and markup, however I am a bit unsure how to make use of components within foreach sections when you need to pass in a viewmodel.
So my current scenario is that I have a view model which looks something like:
function SomePartialViewModel()
{
this.Name = ko.observable();
this.Score = ko.observable();
this.SomeDate = ko.observable();
}
function SomeViewModel()
{
this.DataFromWebServiceCall = ko.observableArray();
this.GetDataFromServer = function(){
// get some data from service and populate DataFromWebSeriviceCall with instances of SomePartialViewModel
}
}
Now in the above we have a POJO to contain partial data, and we have a main view model for the view which will contact a web service or something, and populate its array with instances of the partial. Then this would currently be used like so:
<div id="partial-data" data-bind="template: { name: 'partial-view', foreach: DataFromWebServiceCall }"></div>
<div class="partial-view">
<label data-bind="text: Name"></label>
<label data-bind="text: Score"></label>
<label data-bind="text: SomeDate"></label>
</div>
Now assume the .partial-view is in a script tag with correct template name etc and is a correct template, then the #partial-data is in the main view and wants to display all the instances on the page. Now currently it all works, but I would like to move to a more component based model, and currently we can see that the template relies upon the SomePartialViewModel data, so we have our template and our viewmodel for that component, however the problem is around getting the viewmodel into the component, as currently you register the component at setup time, then you use params to populate chunks of it. However in this case I want to pass in the viewmodel to the component at binding time...
So I was wondering how I can go about doing this, as I imagine I could register the component with a template but no viewmodel, but is there the notion of a data style binding where I can set the $data property and move to a foreach from a template binding on the view?
Hopefully the problem I am trying to solve can be seen and any info would be great.
There are loads of ways to pass values and/or viewmodels to components using the params.
If you use the createViewModel method, you can just pass in the viewmodel via the params and use the partial viewmodel as the component viewmodel:
ko.components.register("partial-view", {
viewModel: {
createViewModel: function (params) {
return params.value;
}
},
template: "<div>Partial View for <b data-bind='text: Name'></b></div>"
});
You can see a working example in this fiddle: http://jsfiddle.net/Quango/fn1ymf9w/
You can define viewModels under viewModels :)
just like defining an observable you can define another viewModel and using "with" binding you can create a component based model you desire.
First you create your components and sub-Components and sub-sub-sub-Components etc viewModels seperately.
var SomePartialViewModel = function()
{
this.Name = ko.observable();
this.Score = ko.observable();
this.SomeDate = ko.observable();
}
var SomeViewModel = function()
{
this.DataFromWebServiceCall = ko.observableArray();
this.GetDataFromServer = function(){
// get some data from service and populate DataFromWebSeriviceCall with instances of SomePartialViewModel
}
this.SPM = new SomePartialViewModel(); // partial-1
}
And then you create a MainViewModel and bind all the main elements here.
var MainViewModel = function() {
var self = this;
self.SVM = new SomeViewModel();
self.SPM = new SomePartialViewModel(); // partial-2
}
ko.applyBindings(new MainViewModel());
then in your html you can create your components obeying the context you created on knockout entities
...
<body>
<div data-bind="with: SVM">
....
<div data-bind="with: SPM">
<!-- partial-1 data -->
</div>
...
</div>
<div data-bind="with: SPM">
<!-- partial-2 data -->
</div>
</body>
...
You may want to create seperate files for your component models and using a modular script loader like Require js you can bind all together to a complete component based knockout web application
I'm trying to use two models in one view, and template using both of them. I'm working with Marionette. Here is me initialization of the view:
main_app_layout.header.show(new APP.Views.HeaderView({
model: oneModel,
model2 : twoModel}
));
Here is my view:
APP.Views.HeaderView = Backbone.Marionette.ItemView.extend({
template : '#view_template',
className: 'container',
initialize: function() {
//This correctly logs the second model
console.log(this.options.model2);
}
});
And here is the template:
<script id="view_template" type="text/template">
<p>{{twoModel_label}} {{oneModel_data}}</p>
<p>{{twoModel_label2}} {{oneModel_data2}}</p>
</script>
It renders everything correctly using the oneModel data, but doesn't render the second, even though it logs it correctly. I'm using Mustache as my templating language.
Can anyone help?
You can override the serializeData method on your view and have it return both models' data:
APP.Views.HeaderView = Backbone.Marionette.ItemView.extend({
// ...
serializeData: function(){
return {
model1: this.model.toJSON(),
model2: this.options.model2.toJSON()
};
}
});
Then your template would look like this:
<script id="view_template" type="text/template">
<p>{{model1.label}} {{model1.data}}</p>
<p>{{model2.label}} {{model2.data}}</p>
</script>
try creating a complex model that contains the two models, this new model will have the other two as properties and you can acccess the properties of each one like this answer explains..
Access Nested Backbone Model Attributes from Mustache Template
I am trying to use Knockout ViewModels as self-contained "widgets" that can be placed into any (or multiple) DOM nodes on the page. I had an approach in Backbone that seemed to work well and I'm trying to convert the concept to Knockout.
In Backbone view I would do something like this, using the RequireJS text plugin to pull the template and inject it into the el:
define(['text!templates/myTemplate.html',], function(templateHTML){
var view = Backbone.View.extend({
initialize:function() {
// yes I know the underscore templating stuff doesn't apply in Knockout
this.template = _.template( templateHTML );
this.render();
},
render:function( ) {
// the $el is provided by external code. See next snippet
this.$el.append(this.template(myData));
return this;
}
// other view behavior here
});
return view;
});
And then some other piece of external code could place that view into an existing DOM node:
new MyBackboneView({el: $('#myExistingDivID')});
In Knockout, the closest I can find to this approach is to have the external code use the Text plugin to pull the template, inject it into the div, and then apply the KO bindings:
var mydiv = $('#myExistingDivID');
mydiv.html(myTemplateHTML);
ko.applyBindings(new MyKOViewModel(), mydiv[0]);
1 - Is there a recommended way in Knockout to have the ViewModel itself inject the external template HTML based on the equivalent of Backbone's "el" concept? The key is that the external (router-ish) code controls where the content will be placed, but the ViewModel controls the actual details of the content and where to get the template.
2 - If yes, should I take this approach, or am I abusing the way that Knockout and MVVM are intended to be used?
You can override the default template source and then use that with the default render engine like
var stringTemplateEngine = new ko.nativeTemplateEngine();
stringTemplateEngine.makeTemplateSource = function (template) {
return new StringTemplateSource(template);
};
ko.setTemplateEngine(stringTemplateEngine);
Quick example I did
http://jsfiddle.net/3CQGT/
I was trying out Backbonejs read through couple of docs. It is an MVC
framework for client side. Inside the views we compile a template and
render them(attach them to DOM, or do some manipulation). Backbone has
a dependency of underscore js, which is the templating stuff.
With Bbone, when manipulating views el comes into picture. My
understanding of el is that it references the DOM Object. If no
dom object is assigned to it, it assumes an empty div.
var choose_view = new SearchView({ el: $("#choose_me") });
So in the above case, the div with id choose_me will be manipulated,
when the choose_view is invoked. So far so good, but what are the
stuff happening below in chronology, I was unable to get, also is
there any redundancy, read the comments for the queries:
// the div with id search_container will be picked up by el
<div id="search_container"></div>
<script type="text/javascript">
SearchView = Backbone.View.extend({
initialize: function(){
this.render();
},
render: function(){
//1. Compile the template using underscore, QUESTION: **what does this mean**?
var template = _.template( $("#search_template").html(), {} );
//2. Load the compiled HTML into the Backbone "el"
this.el.html( template );
}
});
// QUESTION: **When in 2. we have already mentioned, el, can we not over there
provide the div element?**
var search_view = new SearchView({ el: $("#search_container") });
</script>
<script type="text/template" id="search_template">
<label>Search</label>
<input type="text" id="search_input" />
<input type="button" id="search_button" value="Search" />
</script>
Question 1
Compiling template means that you get a template function that you can pass in a data object as argument of the template function. That way, you can evaluate many times your template function with different data objects while it's compiled only once.
compiledTemplate = _.template( $("#search_template").html());
this.el.html(compiledTemplate(data));
another.el.html(compiledTemplate(otherData));
In the example above you compile your template once, then you use it twice.
In the code you have given, you compile and use your template at the same time
So
_.template( $("#search_template").html()); // Create a template function, the result is a function that you can call with a data object as argument
_.template( $("#search_template").html(), data); // Create a template function and call it directly with the data object provided, the result is a string containing html
Ref: http://underscorejs.org/#template
Question 2
You can provide the div element directly, but el is an helper to retrieve the root element of your view on which all DOM events will be delegated.
As indicated in the backbone doc
If you'd like to create a view that references an element already in
the DOM, pass in the element as an option: new View({el:
existingElement})
Ref: http://backbonejs.org/#View-el
I have to get values from a controller method in a view to write into some javascript. In web pages it is as simple as <%=functionName()%>. Is there a way to do this in MVC. I cannot use the model because the javascript has to be available on page load. Any insights appreciated.
Is there a way to do this in MVC
Yes, of course.
I cannot use the model because the javascript has to be available on page load.
Of course that you can use a view model, there's nothing that would prevent you from doing so. So you start by defining it:
public class MyViewModel
{
public string Foo { get; set; }
}
then have a controller action that will populate this view model and pass it the view:
public ActionResult Index()
{
var model = new MyViewModel();
model.Foo = "Hello World";
return View(model);
}
and finally have a strongly typed view to this view model in which:
#model MyViewModel
<script type="text/javascript">
$(function() {
var foo = #Html.Raw(Json.Encode(Model.Foo));
alert(foo);
});
</script>
But now let's suppose that you don't want to pollute your view with javascript but have it in a separate js file instead (which of course is the correct way).
You could embed the value somewhere in your DOM, for example using HTML5 data-* attributes:
<div id="foo" data-model="#Html.Raw(Html.AttributeEncode(Json.Encode(Model)))">
Click me to surprise you
</div>
and then in a separate javascript subscribe to the click event of this element and read the data-* attribute in which we have JSON serialized the entire view model:
$(function() {
$('#foo').click(function() {
var model = $(this).data('model');
alert(model.Foo);
});
});