Backbone: subviews, default "div" wrapper, and delegated events - events

We have two Backbone Views: a parent view (PersonView) and its subview (LocationView).
Their templates, in Mustache notation, are the next:
PersonView template:
<h2>{{fullName}}</h2>
<div>
<h3>Address:</h3>
{{{location}}}
</div>
LocationView template:
<hr />
<dl>
<dt>City:</dt>
<dd>{{city}}</dd>
<dt>Place:</dt>
<dd>{{place}}</dd>
</dl>
NOTE that these templates does NOT have a parent element; so, Backbone will asignate them
the "div" element by default in the "el" property.
In PersonView's "render" method, How can we add the LocationView's rendered HTML into
"PersonView.el" WITHOUT loossing LocationView's events and WITHOUT ADDING the deafult wrapping
"div" element of "LocationView.el"?
We have tried many ways, and if we remove de subview's "el" property, we always loose the
events (in the subviews), but if we keep that "el", then we have problems if we want to
associate it with jQuery events :-(
Anybody has any solution about this?
Thanks in advance.

To elaborate on my comment...
LocationView:
var LocationView = Backbone.View.extend({
tagName: 'dl'
});
LocationView template:
<dt>City:</dt>
<dd>{{city}}</dd>
<dt>Place:</dt>
<dd>{{place}}</dd>
PersonView template:
<h2>{{fullName}}</h2>
<div>
<h3>Address:</h3>
<hr />
{{{location}}}
</div>
Now, in LocationView instances, this.el will be a <dl> instead of a <div>.

Related

Does source binding require a single root element even for non-arrays?

The documentation on source binding has an aside which states:
Important: A single root element should be used in the template when
binding to an array. Having two first level DOM elements will result
in an erratic behavior.
However, I'm finding that this is the case even for non arrays.
I have the following HTML, which sets up two div's populated by two templates. The only difference is that the working template wraps that databound spans in a div.
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://cdn.kendostatic.com/2013.3.1119/js/kendo.all.min.js"></script>
<title>JS Bin</title>
<script id="broken-template" type="text/x-kendo-template">
Foo: <span data-bind="text: foo"></span><br/>
Foo Again: <span data-bind="text: foo"></span>
</script>
<script id="working-template" type="text/x-kendo-template">
<div>
Foo: <span data-bind="text: foo"></span><br/>
Foo Again: <span data-bind="text: foo"></span>
</div>
</script>
</head>
<body>
<div id="broken-div" data-template="broken-template" data-bind="source: this">
</div>
<br/>
<br/>
<div id="working-div" data-template="working-template" data-bind="source: this">
</div>
</body>
</html>
And the JavaScript simply creates a view model with a single property and binds it to both divs:
var viewModel = kendo.observable({foo: "bar"});
kendo.bind($("#broken-div"), viewModel);
kendo.bind($("#working-div"), viewModel);
In both cases, only the first root element and it's children are being bound properly. This suggests that every time I databind to template with more than one element I need to make sure it is wrapped in a single root.
Is this behavior documented somewhere? Is there a bug in Kendo or in my sample code? An explanation for why Kendo requires a single root would be great to hear as well.
(Sample code as a jsfiddle)
It's not documented except in the one place you mentioned. Such is the state of Kendo UI documentation - it's less than complete. I've been using Kendo UI for three years and as far as I can tell you, this is its default behavior and not a bug. Unfortunately, it's one of the many quirks you simply learn (stumble upon) from experience.

Kendo grouped-listview

I would like to know how to modify the example grouped listview that comes with kendo mobile.
The list view shows both flat view and grouped view. How do you make the items in the list view clickable so they will navigate to a different web page when clicked?
I've tried creating a template with an anchor tag and href and it works in IE but does nothing when clicked on the android phone.
//The Template
<script type="text/x-kendo-tmpl" id="template">
<div class="myclass">
#:name#
</div>
</script>
//The data binding
function mobileListViewDataBindInitGrouped() {
$("#grouped-listview").kendoMobileListView({
dataSource: kendo.data.DataSource.create({ data: groupedData, group: "letter" }),
template: kendo.template($("#template").html()),
fixedHeaders: true
});
}
Thanks
After some trial and error I have found that if i remove the div tag in the template, the anchor tags work correctly. Not sure if this is a bug or by design.
Thanks Whizkid747 for your help.
//Updated Template (removed <div>)
<script type="text/x-kendo-tmpl" id="template">
#:name#
</script>

Is it possible to open CKEditor Insert-Image Component programmatically?

For example, if I have a ready instance of CKEDITOR, and on that same page I have a list of pictures, with this markup:
<div class="galleryPictures">
<a href="#image-id-1" data-id="1" data-img-src="/pictures/image-1.jpg" class="galleryPicture">
<img src="/pictures/image-1.jpg" />
</a>
<a href="#image-id-2" data-id="2" data-img-src="/pictures/image-2.jpg" class="galleryPicture">
<img src="/pictures/image-2.jpg" />
</a>
<a href="#image-id-3" data-id="3" data-img-src="/pictures/image-3.jpg" class="galleryPicture">
<img src="/pictures/image-3.jpg" />
</a>
</div>
And I have following jQuery click handler delegated to these a.galleryPicture items:
$(document).ready(function() {
$('.galleryPictures').on('click', 'a.galleryPicture', function() {
// when this accours I would like to open CKEditor's
// Insert-Image Component, and to get the "url" field filled with
// $(this).data('img-src'); value
});
});
Is it possible to trigger / open Insert-Image programmatically?
Found it. Might be of help to someone else:
With a simple inspection with Firebug I've seen that the <a> which on click triggers the opening of the Insert-Image component contains this function call in it's onclick attribute:
CKEDITOR.tools.callFunction(51,{});
// second argument is {} (an empty js-object), it the original the <a> onclick it was like this:
// CKEDITOR.tools.callFunction(51, this); meaning it was sending the instance of that element
After this call it is possible to do something like this:
CKEDITOR.tools.callFunction(51,{});
// a failsafe if jQuery doesn't find the specified element after the function is executed
setTimeout(function() {
$('#cke_69_textInput').val('someImageUrl');
}, 50);

KendoMobile ui template not rendering css How to make the template render with kendo stylng in view?

Basically the template wont render to a ScrollView using kendo.render(template, response) but WILL work with content = template(response) - BUT this has no styling in view -- see comment below
How to make the template render with kendo stylign in view?
BTW response from api call is JSON:
{"event_id":"5","stamp":"2013-01-24 06:00:00","type":"Event Type","loc":"Location","status":"1"}
<!-- eventDetail view -------------------------------------------------------------------------------------------------->
<div data-role="view" id="view-eventDetail" data-show="getEventDetailData" data-title="eventDetail">
<header data-role="header">
<div data-role="navbar">
<span data-role="view-title"></span>
<a data-align="right" data-role="button" class="nav-button" href="#view-myEvents">Back</a>
</div>
</header>
<div id="eventDetail" data-role="page"></div>
</div>
<script id="eventDetail-template" type="text/x-kendo-template">
--><form id="addEventForm"><p>
<input name="event_type" id="event_type" data-min="true" type="text" value="#= type #" />
</p>
<p>
<input name="event_loc" id="event_loc" data-min="true" type="text" value="#= loc #" />
</p>
<p>
<input name="event_date_time" id="event_date_time" data-min="true" type="datetime" value="#= stamp#" />
</p>
<p>
Share this
<input data-role="switch" id="event_share" data-min="true" checked="checked" value="1"/></p>
<p>
<input type="button" id="eventCancelButton" style="width:30%" data-role="button" data-min="true" value="Cancel" />
<input type="submit" id="eventDoneButton" style="width:30%" data-role="button" data-min="true" value="Done" />
</p></form><!--
</script>
<script>
//eventDetail engine
function getEventDetailData(e) {
$.ajax({
url: 'http://localhost/mpt/website/api/event_details.php?',
type: "GET",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: { userID: 2, eventID: e.view.params.id },
success: function(response) {
console.log(response);
var template = kendo.template($("#eventDetail-template").html()),
content = template(response);//works but no kendo css
//content = kendo.render(template, response);not working
$("#eventDetail")
.kendoMobileScrollView()
.data("kendoMobileScrollView")
.content("<!--" + content + "-->");
}
});
}</script>
The widget classes (like km-button) are not added until the widget is initialized.
The template() and render() functions just return the template as a string with the data replaced (replaces #=foo# with the value of the foo property) but does not init all the widgets. In fact, it coldn't initialize the widgets if it wanted to singe it just returns a text string, not DOM elements. The initialization of the widgets is usually done by the parent widget that is using the template.
render() is not working in your case because its 2nd argument is supposed to be an array. All it does is call the given template function once per item in the array and concatenate the results. If you instead did:
var content = kendo.render(template, [response]); // wrap response in an array
it would return the same text string as template(response). It just provides a way to apply the same template to many items at once.
Normally when you create a widget, in your case calling .kendoMobileScrollView() you would expect it to turn any HTML contents of that element into widgets too, but it looks like the ScrollView widget doesn't do this. I think its intent may have been to just display pages of static content, not other widgets.
There is a Kendo method that isn't listed in the docs, kendo.mobile.init(contents); that you might be able to use to turn your template string into widgets. When I tried it in a jsFiddle it threw some error for me, but you could try something like:
var content = template(response); // apply response to template
var contentElements = $(content); // turn the string into DOM elements
kendo.mobile.init(contentElements); // turn elements into widgets (this throws error for me)
$("#eventDetail").html(contentElements); // add contents to the desired element
$("#eventDetail").kendoMobileScrollView(); // create the scroll view
Also, what is with the end and begin comment bits hanging off the ends of the template? I don't see why those are needed. Might be better to remove them.
The ScrollView widget is supposed to take a series of <div> elements as its children. It then pages between them as you swipe left/right across the control. I don't see you adding a series of <div>s anywhere.

Can you call ko.applyBindings to bind a partial view?

I'm using KnockoutJS and have a main view and view model. I want a dialog (the jQuery UI one) to popup with another view which a separate child view model to be bound to.
The HTML for the dialog content is retrieved using AJAX so I want to be able to call ko.applyBindings once the request has completed, and I want to bind the child view model to just the portion of the HTML loaded via ajax inside the dialog div.
Is this actually possible or do I need to load ALL my views and view models when the page initially loads and then call ko.applyBindings once?
ko.applyBindings accepts a second parameter that is a DOM element to use as the root.
This would let you do something like:
<div id="one">
<input data-bind="value: name" />
</div>
<div id="two">
<input data-bind="value: name" />
</div>
<script type="text/javascript">
var viewModelA = {
name: ko.observable("Bob")
};
var viewModelB = {
name: ko.observable("Ted")
};
ko.applyBindings(viewModelA, document.getElementById("one"));
ko.applyBindings(viewModelB, document.getElementById("two"));
</script>
So, you can use this technique to bind a viewModel to the dynamic content that you load into your dialog. Overall, you just want to be careful not to call applyBindings multiple times on the same elements, as you will get multiple event handlers attached.
While Niemeyer's answer is a more correct answer to the question, you could also do the following:
<div>
<input data-bind="value: VMA.name" />
</div>
<div>
<input data-bind="value: VMB.name" />
</div>
<script type="text/javascript">
var viewModels = {
VMA: {name: ko.observable("Bob")},
VMB: {name: ko.observable("Ted")}
};
ko.applyBindings(viewModels);
</script>
This means you don't have to specify the DOM element, and you can even bind multiple models to the same element, like this:
<div>
<input data-bind="value: VMA.name() + ' and ' + VMB.name()" />
</div>
I've managed to bind a custom model to an element at runtime. The code is here: http://jsfiddle.net/ZiglioNZ/tzD4T/457/
The interesting bit is that I apply the data-bind attribute to an element I didn't define:
var handle = slider.slider().find(".ui-slider-handle").first();
$(handle).attr("data-bind", "tooltip: viewModel.value");
ko.applyBindings(viewModel.value, $(handle)[0]);
You should look at the with binding, as well as controlsDescendantBindings http://knockoutjs.com/documentation/custom-bindings-controlling-descendant-bindings.html

Resources