Ready event for templates - jsviews

In JsViews i can bind events in the following way:
<li id="myElement" data-link="{on 'click' eventHandler}">Some Content</li>
This will execute the method "eventHandler" after a click.
But I need an event which will be fired when the template is loaded. I tried "ready" or "show", but nothings works. Is there a event which can handle this?

The {on xxx eventHandler} handles events on HTML elements, such as mouse events, submit, change, blur, etc.
With JsViews, the loading of the template happens directly as a result of your own code calling the link method. So elements in the rendered template will have been rendered during that call, and immediately after you can run whatever code you want to call after rendering and linking, such as using jQuery to find your <li> element, and act on the element
JsViews also provides many life-cycle events on tags, so if you want you can create a custom tag just for handling those events:
For example, try running the following code:
<span id="result"></span>
<script>
var data = {};
$.views.tags("test", {
attr:"none",
render: function(data) {
debugger;
},
onBind: function(tagCtx, linkCtx) {
var elem = this.parentElem;
elem.textContent += " added text";
}
});
var myTmpl = $.templates('<ul><li id="myElement" data-link="{test}">Some Content</li></ul>');
myTmpl.link("#result", data);
$("#myElement").css('color', 'red');
</script>

You could use an onload event:-
https://www.w3schools.com/jsref/event_onload.asp
and attach that to the template itself. If you're limited in your options or need to do it in a specific way, explain the use case and why you want to do it a certain way and we'll try to help.
All the best,
Phil

Related

How to Attach Events to Table Checkboxes in Material Design Lite

When you create a MDL table, one of the options is to apply the class 'mdl-data-table--selectable'. When MDL renders the table an extra column is inserted to the left of your specified columns which contains checkboxes which allow you to select specific rows for actions. For my application, I need to be able to process some JavaScript when a person checks or unchecks a box. So far I have been unable to do this.
The problem is that you don't directly specify the checkbox controls, they are inserted when MDL upgrades the entire table. With other MDL components, for instance a button, I can put an onclick event on the button itself as I'm specifying it with an HTML button tag.
Attempts to put the onclick on the various container objects and spans created to render the checkboxes has been unsuccessful. The events I attach don't seem to fire. The closest I've come is attaching events to the TR and then iterating through the checkboxes to assess their state.
Here's the markup generated by MDL for a single checkbox cell:
<td>
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect mdl-data-table__select mdl-js-ripple-effect--ignore-events is-upgraded" data-upgraded=",MaterialCheckbox">
<input type="checkbox" class="mdl-checkbox__input">
<span class="mdl-checkbox__focus-helper"></span>
<span class="mdl-checkbox__box-outline">
<span class="mdl-checkbox__tick-outline"></span>
</span>
<span class="mdl-checkbox__ripple-container mdl-js-ripple-effect mdl-ripple--center">
<span class="mdl-ripple"></span>
</span>
</label>
</td>
None of this markup was specified by me, thus I can't simply add an onclick attribute to a tag.
If there an event chain I can hook into? I want to do it the way the coders intended.
It's not the nicest piece of code, but then again, MDL is not the nicest library out there. Actually, it's pretty ugly.
That aside, about my code now: the code will bind on a click event on document root that originated from an element with class mdl-checkbox.
The first problem: the event triggers twice. For that I used a piece of code from Underscore.js / David Walsh that will debounce the function call on click (if the function executes more than once in a 250ms interval, it will only be called once).
The second problem: the click events happens before the MDL updates the is-checked class of the select box, but we can asume the click changed the state of the checkbox since last time, so negating the hasClass on click is a pretty safe bet in determining the checked state in most cases.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
$(document).on("click", ".mdl-checkbox", debounce(function (e) {
var isChecked = !$(this).hasClass("is-checked");
console.log(isChecked);
}, 250, true));
Hope it helps ;)
We currently don't have a way directly to figure this out. We are looking into adding events with V1.1 which can be subscribed to at Issue 1210. Remember, just subscribe to the issue using the button on the right hand column. We don't need a bunch of +1's and other unproductive comments flying around.
One way to hack it is to bind an event to the table itself listening to any "change" events. Then you can go up the chain from the event's target to get the table row and then grab the data you need from there.
You could delegate the change event from the containing form.
For example
var form = document.querySelector('form');
form.addEventListener('change', function(e) {
if (!e.target.tagName === 'input' ||
e.target.getAttribute('type') !== 'checkbox') {
return;
}
console.log("checked?" + e.target.checked);
});

button event with jQuery

I have an id of the button element like this: '#edit-field-project-dnr-und-0-remove-button'
I want to add an event in this button id for instance:
$('#edit-field-project-dnr-und-0-remove-button').click(function (){
calculateDonorSum();
});
This button is ajax button whenever this is clicked old id that is '#edit-field-project-dnr-und-0-remove-button' is replaced into '#edit-field-project-dnr-und-1-remove-button' and so on but no event is fired in the previous button id. Is there any way to fix this ?
When you do this:
$('#edit-field-project-dnr-und-0-remove-button').click(function (){
calculateDonorSum();
});
This searches the current DOM for any element that has an id="edit-field-project-dnr-und-0-remove-button" and attaches an event handler directly to that DOM element.
If you remove that DOM element and create some new DOM element or add a new DOM element, that new DOM element will NOT have this event handler attached to it unless you run some new code to attach an event handler to the new element.
For dynamic elements, it is also possible to use delegated event handling, but you haven't really described enough of what you're doing for us to know how to recommend that. I can't tell if you're adding a new button or changing the ID on the current button.
If you are adding a new button and want all new buttons of this type to have this event handler, then you can use delegated event handling. Delegated event handling works like this:
$("some static common parent selector").on("click", "some common child selector", fn);
So, if your buttons were all in a id="container" div and all had a common class name on them class="calcButton", then you could use:
$("#container").on("click", ".calcButton", function() {
calculateDonorSum();
});
And, all buttons in the container with that class would have this event handler, even if they are dynamically created after the event handler is defined.
Some other references on delegated event handling:
jQuery .live() vs .on() method for adding a click event after loading dynamic html
Does jQuery.on() work for elements that are added after the event handler is created?
Should all jquery events be bound to $(document)?
JQuery Event Handlers - What's the "Best" method
consider using jQueries attribute starts with, contains, or ends with selectors
//button id starts with 'edit-field-project-dnr-und-' and ends with '-remove-button'
$("[id^=edit-field-project-dnr-und-][id$=-remove-button]").click(function () {
calculateDonorSum();
});
if these buttons are created dynamically, use
$('#some-parent-container').on("click","[id^=edit-field-project-dnr-und-][id$=-remove-button]", function(){
calculateDonorSum();
})
instead of .click()
//button id starts with
$("[id^=button-]").click(function () {
calculateDonorSum();
});
//button id ends with
$("[id$=-remove]").click(function () {
calculateDonorSum();
});
//button id contains
$("[id*=-remove]").click(function () {
calculateDonorSum();
});
this works, here, made a fiddle
http://jsfiddle.net/MzPEg/1/
in general use this approach ONLY if you don't have control over the naming/creation of the original buttons. these selectors are not as fast as $('#id') and it's a bit sloppy. but it will work in a pinch.
It appears that the id of the field on which the onclick event is supposed to occur is changing, yet you only handle the first id. If you do not want to make all of these ids the same, you could put the click event handler on a parent wrapper div.
You can do as this:
$('#edit-field-project-dnr-und-0-remove-button').click(function (e){
e.preventDefault();
calculateDonorSum();
$(this).attr('id','edit-field-project-dnr-und-1-remove-button');
});
Using an advanced selector that matches the beginning part of the id AND the ending part:
$('[id^="edit-field-project-dnr-und"][id$="remove-button"]').on('click', function(){...});

What is the 'angular' way of displaying a tooltip / lightbox?

I've been looking around and have not been quite able to get a clear path to the 'angular' way of accomplishing the following. What I'm trying to achieve is displaying a tooltip with information when hovering over a link within an ng-repeat loop. Based on my research, I understood that this is part of the view, and so I should probably handle this in a directive. So, I created an attribute directive called providertooltip. The html declaration is below:
<table>
<tr id="r1" ng-repeat="doc in providers">
<td>
<a providertooltip href="#{{doc.Id}}" ng-mouseover="mouseOverDoc(doc)" ng-mouseleave="mouseLeave()">{{doc.FirstName}} {{doc.LastName}}</a>
</td>
</tr>
</table
<div id="docViewer" style="display:hidden">
<span>{{currentDoc.FirstName}} {{currentDoc.LastName}}</span>
</div>
In the module, I declare my directive, and declare my mouseOver and mouseLeave functions in the directive scope. I also 'emit' an event since this anchor is a child scope of the controller scope for the page. On the controller function (docTable ) which is passed as a controller to a router, I listen for the event. Partial implementation is seen below:
app.directive("providertooltip", function() {
return {
restrict : 'A',
link: function link(scope, element, attrs) {
//hover handler
scope.mouseOverDoc = function(doc){
scope.currentDoc = doc;
scope.$emit('onCurrentDocChange');
element.attr('title',angular.element('#docViewer').html());
element.tooltipster('show');
//docViewer
};
scope.mouseLeave = function() {
element.tooltipster('hide');
}
}
}});
function docTable(docFactory, $scope, $filter, $routeParams) {
$scope.$on('onCurrentDocChange',function(event){
$scope.currentDoc = event.targetScope.currentDoc;
event.stopPropagation();
});
}
Ok, so here is my question. All of the works as expected; Actually, the tooltip doesn't really work so if someone knows a good tooltip library that easily displays div data, please let me know. But, what I'm really confused about is the binding. I have been able to get the tooltip above to work by setting the title ( default tooltip behavior ), but I can see that the binding has not yet occured the first time I hover of a link. I assume that the onCurrentDocChange is not synchronous, so the binding occurs after the tooltip is displayed. If I hover over another link, I see the previous info because as I mentioned the binding occurs in an asynchronous fashion, i.e., calling scope.$emit('onCurrentDocChange') doesn't mean the the parent scope binds by the time the next line is called which shows the tooltip. I have to imagine that this pattern has to occur often out there. One scope does something which should trigger binding on some other part of the page, not necessarily in the same scope. Can someone validate first that the way I'm sending the data from one scope to the other is a valid? Moreover, how do we wait until something is 'bound' before affecting the view. This would be easier if I let the controller mingle with the view, but that is not correct. So, I need the controller to bind data to the scope, then I need the view to 'display a tooltip' for an element with the data. Comments?
To go the angular way correctly start your directive like:
...
directive('showonhover',function() {
return {
link : function(scope, element, attrs) {
element.parent().bind('mouseenter', function() {
element.show();
});
element.parent().bind('mouseleave', function() {
element.hide();
});
}
...
Or start with http://angular-ui.github.io/ link to go the angular-way UI. Look into the bootstrap-ui module - pure angular bootstrap widgets implemented as directives. You can get a clue how the tooltip binding implemented directly from the source of the module - https://github.com/angular-ui/bootstrap/blob/master/src/tooltip/tooltip.js
Also here is another example - (having jQuery and bootstrap scripts included) - use the ui-utils module Jquery passthrough directive ui-jq'. It allows to bind Jquery plugins ( style of $.fn ) directly as angular directive.
Here is their example for binding twitter bootstrap tooltip.
<a title="Easiest. Binding. Ever!" ui-jq="tooltip">
Hover over me for static Tooltip</a>
<a data-original-title="{{tooltip}}" ui-jq="tooltip">Fill the input for a dynamic Tooltip:</a>
<input type="text" ng-model="tooltip" placeholder="Tooltip Content">
<script>
myModule.value('uiJqConfig', {
// The Tooltip namespace
tooltip: {
// Tooltip options. This object will be used as the defaults
placement: 'right'
}
});
</script>
Also look into the official angular documentation for writing directives examples,
and have a happy coding time with Angular!

knockout.js data-bind 'with' conflicts with jQuery change event

For some reason, when I use the data-bind="with: detailedStudent" the jQuery change() binding does not get called. I'm dynamically populating the select options but I'm not sure that should matter. This is some of the code I'm using just to try to give a decent picture of what's going on:
var viewModel;
$(document).ready(function() {
viewModel = new StudentViewModel();
ko.applyBindings(viewModel);
// this change event is not getting called, but if i put the onchange directly into the html as an attribute, it works fine.
$("#accountDialog").find("#mySelect").change(function() {
alert('hi');
}
}
function Student(data) {
var self = this;
ko.mapping.fromJS(data, {}, this);
}
function StudentViewModel() {
var self = this;
this.students = ko.observableArray([]);
this.detailedStudent = ko.observable();
}
<div id="accountDialog" class="modal hide fade" data-bind="with: detailedStudent">
<select id="mySelect" name="mySelect" data-bind="value: GraduationClassId"></select>
</div>
The with binding is a wrapper to the template binding. It copies off the child elements and uses them as the template. So, if your detailedStudent is changing, then KO will be rendering new elements each time that did not have the event handler attached to it.
Some alternatives:
use a binding to attach the event handler (can use event binding)
create a manual subscription against your detailedStudent observable and perform your action in the view model (best option, if your action does not involve DOM manipulation)
try to use a delegated event handler like jQuerys $.on() http://api.jquery.com/on/.
If the action does not involve DOM manipulation, then I agree with RP Niemeyer, the manual subscription is the best option.
However, usually we will have some event with DOM manipulation, for example, to setup the jquery dialog / datepicker plugin to your property. I regard the custom binding would be the best option. The custom binding will work perfectly with the "with" binding clause to setup event handlers to arbitary javascript function.
You could read through this and it is not as hard as it seems to be.
http://knockoutjs.com/documentation/custom-bindings.html

jQuery.click(): Can I get a reference to the synthetic event object passed to event handlers?

I have an <a> inside a <TD>, and I'm trying to have clicks on the <TD>, but outside the <A>, act like they were clicks on the <a>. I'm almost there:
HTML:
<TD class="somethingPretty">
Text
</td>
JS:
$('.anchor').click(function(ev){return confirm("go ahead?");});
$('somethingPretty').click(function(ev){
if($('.anchor').click()){
document.location = $('.anchor').attr('href');
}
}
The problem with this is that jQuery.click returns undefined, and I can't see how to get at the event object that's passed to the click handlers so I can interrogate it with isPropagationStopped and isDefaultPrevented. What's the right way to solve this problem?
Sometimes asking the question clearly is the best way to find an answer. Some strategic poking around the jQuery source led me to the following solution(using the markup above):
$('.somethingPretty').click(function(ev){
var syntheticClick = new $.Event("click");
syntheticClick.stopPropagation();
$('.anchor').trigger(syntheticClick);
if(syntheticClick.isDefaultPrevented()) return;
document.location = $('.anchor').attr('href');
}
This works for all event handlers except live-bound ones (those don't execute; my users will have to learn to click the anchor itself for them!). The tricky part here is that trigger takes a jQuery.Event in addition to the documented string.
How about this?
var a = $('.somethingPretty .anchor');
var td = $('.somethingPretty');
a.click( function(ev) { return confirm("go ahead?"); } );
td.click( function() { a.click(); } );
Did you try something like:
$("td.outer").add("td.outer a").click(function() {
// do stuff
});
You're going to want to find some way to ensure that whatever is in the function runs only once, since a click on the <a> will count both as a click on the <td> and the <a>.

Resources