HTML element not in a ready state after View.Render called - backbone.js

I have a View code and the render inside the code looked like following.
render: function() {
var $el = $(this.el);
$el.html(this.template({diarysCollection: this.collection}));
$("#updateStatusContent").charCount({
css:'counter',
cssWarning:'counter_warning',
cssExceeded:'counter_exceeded',
allowed:750,
warning:50,
counterText:text_characters_left + " "
});
.....
But the html element updateStatusContent present in the template is not ready so jquery charcount dosen't work.

Try referencing the element within the scope of the current view:
this.$('#updateStatusContent')
Documentation:
view.$(selector)

Related

resulting HTML from $compile(custom-directive) doesn't bind {{values}}

I want to dynamically add Angular custom Directives, but the directive resulting from $compile(directive) doesn't have the 2-ways binding.
Here's my simplified problem: I am using MapBox, and I want to use Directives for the the markers' popup to show, for example, the markers' title. MapBox wants HTML as a String to put inside the popup, so my idea was to pass a $compiled directive, something like $compile('<myDirective></myDirective>')($scope).html().
It replace the directive with its template, but {{values}} are not solved.
I have something like this to create the popup
map.featureLayer.on('layeradd', function(e)
{
var marker = e.layer;
var popupContent = ctrl.createPopup(marker);
// popupContent should be HTML as String
marker.bindPopup(popupContent);
});
ctrl.createPopup(marker) call a function of the controller, that does:
this.createPopup = function(marker)
{
var popup = "<mapbox-marker-popup"
+" title = "+marker.feature.properties.title
+"</mapbox-marker-popup>";
// should return HTML as String
return ($compile(popup)($scope).html());
}
where mapbox-marker-popup is a directive specified as follow:
/* ===== MARKER POPUP DIRECTIVE=========== */
.directive('mapboxMarkerPopup', function() {
return {
restrict: 'E',
template: [
"<p>{{title}}</p>",
].join(""),
scope:
{
title: '#'
}
}
})
Anyway... mapboxMarkerPopup is not working. title is shown as {{title}}
[UPDATE2 - {{title}} not solved]
Here's the JSFiddle
You need to return the compile angular element instead of returning html of that element. Only returning the html will never carry the angular two way binding. By using compiled object you can keep your binding working.
Code
this.createPopup = function(marker) {
var popup = "<mapbox-marker-popup" +
"title = '" + marker.feature.properties.title + "'"
+ "</mapbox-marker-popup>";
return ($compile(popup)($scope)[0]);
};
Working Fiddle
Update
$compile
Compiles an HTML string or DOM into a template and produces a template
function, which can then be used to link scope and the template
together.
Take a look at this link will give you more idea

angularjs directive rendered by third party component is not working

I have a simple angularjs directive that I use to show a tooltip.
<div tooltip-template="<div><h1>Yeah</h1><span>Awesome</span></div>">Click to show</div>
It works fine but now I'm trying to use it inside a timeline javascript component (visjs.org)
I can add items with html to this timeline like this
item...
item.content = "<div tooltip-template='<div><h1>Yeah</h1><span>Awesome</span></div>'>Click to show</div>";
$scope.timelineData.items.add(item);
The item is well displayed on the page BUT the code of the tooltip-template directive is never reached.
I suspect that because a third party component is rendering the item, the dom element is not read by angular.
I've tried to do a $scope.$apply(), $rootScope.$apply but the result is the same. The directive is never reached.
How can I tell angular to read my dom to parse these directives ?
Here is the directive code :
.directive("tooltipTemplate", function ($compile) {
var contentContainer;
return {
restrict: "A",
link: function (scope, element, attrs) {
var template = attrs.tooltipTemplate;
scope.hidden = true;
var tooltipElement = angular.element("<div ng-hide='hidden'>");
tooltipElement.append(template);
element.parent().append(tooltipElement);
element
.on('click', function () { scope.hidden = !scope.hidden; scope.$digest(); })
$compile(tooltipElement)(scope);
}
};
});
Edit
Added plunker : http://plnkr.co/edit/lNPday452GiZJBhMH4Kl?p=preview
I tried to do the same thing and came with a solution by manually creating scope and compile'ng the html of the directive with the scope using $compile method. Below a snippet
I did the below part inside a directive that created the timeline . Using the scope of that directive ,
var shiftScope = scope.$new(true);
shiftScope.name = 'Shift Name'
var shiftTemplate = $compile('<shift-details shift-name="name"></shift-details>')(shiftScope)[0];
I passed shiftTemplate as the content and it worked fine .
But trying to do this for >50 records created performance issues .

Compile a template without passing scope

Question
In AngularJS, is there a way to convert a string template into markup without using scope or a directive?
Explanation
I have a service which allows me to create new angular apps dynamically. It builds up the DOM for the new app, then runs angular.boostrap on the element.
Currently, the DOM is created like this:
var element = document.createElement('div');
element.setAttribute('app', '');
element.setAttribute('size', 'small');
...
element.className = 'app layout--relative';
There are many attributes, classes, child elements, etc, so creating the markup in this way is not ideal. It would be better to use a template.
Normally I would use $compile to convert a string template into markup, but because I have not run angular.bootstrap yet, there is no scope in order to use $compile(template)(scope);
What I have tried
Create a div, then replace the innerHTML with the template string
This works, but all of the attributes and classes on the root element need to be added separately.
var element = document.createElement('div');
element.innerHTML = template;
Remove scope after the template has compiled
This works, but I would prefer to avoid scope altogether:
var scope = $rootScope.$new();
var element = $compile(template)(scope);
scope.$destroy();
You could use the $interpolate service for string substitution like this:
var template = '<div app size="{{size}}" class="{{className}}">' +
'<span>Hello {{name}}!</span>' +
'</div>';
$interpolate(template)({
size: 'small',
className: 'app layout--relative',
name: 'World'
});
and the result would be like this:
<div app size="small" class="app layout--relative">
<span>Hello World!</span>
</div>
Hope this helps.

Backbone Marionette CompositeView Rendering/Usage

I must be doing something wrong because I can't get the non-collection portion of the CompositeView to render with a specified template. No matter how I try to specify the template, it doesn't render as expected.
Per the docs at https://github.com/derickbailey/backbone.marionette/blob/master/docs/marionette.compositeview.md
I've tried providing a string that points at a template stored in a script tag, and a pre-compiled template as the template argument like so:
Backbone.CompositeView.extend({
template: _.template( "<div><span class='items'></span></div>" )
});
Here's a live attempt in jsfiddle: http://jsfiddle.net/2PgrS/4/
You never rendered your view.
var view = new MyCompositeView({
collection: collection
});
// render the view
view.render();
view.$el.appendTo( "body" );
http://jsfiddle.net/derickbailey/XJLxv/1/

Backbone.js turning off wrap by div in render

I have model Post and collection Posts. And want to make form with list of all post in <select id="multi" multiple="multiple">. So i have to make a PostView render inside my #multi with just this template:
<option value=""><%= title %></option>
But finally I get it wrapped with div. Is there any solution for not wrapping this template with <div>?
If you don't define an el (or tagName) for the view (in the class or during instantiation) the view will be placed inside a div tag. http://documentcloud.github.com/backbone/#View-el
var PostView = Backbone.View.extend({
tagName: 'option'
});
UPDATE
Starting v0.9.0, Backbone has view.setElement(element) to get this done.
var PostView = Backbone.View.extend({
initialize: function() {
var template = _.template('<option value=""><%= title %></option>');
var html = template({title: 'post'});
this.setElement(html);
}
});
If you don't want to have the view wrap your HTML, you'll have to do a few things:
Replace this.el entirely
Call delegateEvents on the new el
render: function(){
var html = "some foo";
this.el = html;
this.delegateEvents(this.events);
}
Since Backbone generates a div or other tag (based on your tagName setting for the view), you have to replace it entirely. That's easy to do. When you do that, though, you lose your declared events because Backbone uses jQuery's delegate under the hood to wire them up. To re-enable your declared events, call delegateEvents and pass in your events declarations.
The result is that your view.el will be the <option> tag that you want, and nothing more.
In version 0.9.0, Backbone introduced view.setElement(element) to handle this operation.

Resources