D3.js brushend function not properly called - function

I made a module that draws a bar chart including a d3.svg.brush(). Part of my code is
Bar.prototype.init = function ( ) {
//...
this.brush = d3.svg.brush()
.y( this.y)
.on("brushend", this.brushend);
console.log(this.brushend); // works
}
Bar.prototype.brushend = function() {
console.log(this.brush); // undefined. why?
}
To access this.* values, I cannot make brushend function a normal function by using function brushend() or var brushend = function().
How should I call it properly?

D3 will call the event handler provided for its brushend event much like event handlers for normal DOM events will get called. For standard events this will reference the element the event occured upon. This rule does also apply to D3's brush event handlers where this references the group containing the DOM elements of the brush. Obviously, this group doesn't have a property brush you could reference by using this.brush from with the handler.
A workaround would be to save your reference by using a closure:
Bar.prototype.init = function ( ) {
//...
this.brush = d3.svg.brush()
.y(this.y)
.on("brushend", this.brushend()); // Get handler by calling factory
}
// A factory returning the handler function while saving 'this'.
Bar.prototype.brushend = function() {
var self = this; // Save a reference to the real 'this' when the factory is called.
return function() { // Return the handler itself.
// By referencing 'self' the function has access to the preserved
// value of 'this' when the handler is called later on.
console.log(self.brush);
};
}

Related

TVML listItemLockup click event

I'm using the 'Compilation.xml' template from the TVMLCatalog
I'd like to add a button click event to a 'listItemLockup'
<listItemLockup>
<ordinal minLength="2" class="ordinalLayout">0</ordinal>
<title>Intro</title>
<subtitle>00</subtitle>
<decorationLabel>(3:42)</decorationLabel>
</listItemLockup>
I've tried adding:
App.onLaunch = function(options) {
var templateURL = 'http://localhost:8000/hello.tvml';
var doc = getDocument(templateURL);
//doc.addEventListener("select", function() { alert("CLICK!") }, false);
var listItemLockupElement = doc.getElementsByTagName("listItemLockup");
listItemLockupElement.addEventListener("select", function() { alert("CLICK!") }, false);
}
addEventListener
void addEventListener (in String type, in Object listener, in optional Object extraInfo)
Is "select" the correct type?
I've been using the following tutorials
http://jamesonquave.com/blog/developing-tvos-apps-for-apple-tv-with-swift/
http://jamesonquave.com/blog/developing-tvos-apps-for-apple-tv-part-2/
Update
I'm getting an error
ITML <Error>: doc.getElementsByTagName is not a function. (In 'doc.getElementsByTagName("listItemLockup")', 'doc.getElementsByTagName' is undefined) - http://localhost:8000/main.js - line:27:58
I tried adding this to the 'onLaunch'
var listItemLockupElements = doc.getElementsByTagName("listItemLockup");
for (var i = 0; i < listItemLockupElements.length; i++) {
//var ele = listItemLockupElements[i].firstChild.nodeValue;
listItemLockupElements[i].addEventListener("select", function() { alert("CLICK!") }, false);
}
I'll see about the error first
Cross Post: https://forums.developer.apple.com/thread/17859
More common example I have seen by Apple is to define a single overall listener like:
doc.addEventListener("select", Presenter.load.bind(Presenter));
In your xml, assign unique ids to elements, or give them ways to identify them.
For example, the beginning would be something like:
load: function(event) {
var self = this,
ele = event.target,
attr_id = ele.getAttribute("id"),
audioURL = ele.getAttribute("audioURL"),
videoURL = ele.getAttribute("videoURL")
And then you can do whatever you want with your item.
if(audioURL && (event.type === "select" || event.type === "play")) {
//
}
My advice would be to study the Presenter.js file more carefully for this pattern.
Edit:
Answering your "Update" related to doc.getElementsByTagName is not a function. "doc" does not actually exist, but the general pattern is to get it with
var doc = getActiveDocument();
I assumed you would know the above.
Does that fix it?
var listItemLockupElement = doc.getElementsByTagName("listItemLockup”);
In this case, the listItemLockupElement is a NodeList, not an element. You can either iterate through the list and add an event listener to each listItemLockup, or you could add the event listener to the containing element.
When addressing items in a NodeList, you use the item(i) method rather than the standard array access notation:
listItemLockupElements.item(i).addEventListener("select", function() { })
See: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/item
Adding event listeners is straightforward if you're using atvjs framework.
ATV.Page.create({
name: 'mypage',
template: your_template_function,
data: your_data,
events: {
select: 'onSelect',
},
// method invoked in the scope of the current object and
// 'this' will be bound to the object at runtime
// so you can easily access methods and properties and even modify them at runtime
onSelect: function(e) {
let element = e.target;
let elementType = element.nodeName.toLowerCase();
if (elementType === 'listitemlockup') {
this.doSomething();
}
},
doSomething: function() {
// some awesome action
}
});
ATV.Navigation.navigate('mypage');
Disclaimer: I am the creator and maintainer of atvjs and as of writing this answer, it is the only JavaScript framework available for Apple TV development using TVML and TVJS. Hence I could provide references only from this framework. The answer should not be mistaken as a biased opinion.

error #1006 value is not a function

I have a problem with my project.
I use SWFLoader to load a .swf file and addEvent when it completed:
function completeHandler(event:LoaderEvent):void {
var mainObj:Object = Object(loader.rawContent.CTN_PROFILES);
var obj : Object = { };
mainObj.playerOptions(obj);
}
but always get this Error:#1006 value is not a function.
And it happened at :
mainObj.playerOptions(obj);
When i trace mainObj at console, i get all of its methods:
{Profiles}
Extends: {Object}
function tabInfoClickHandle(flash.events::MouseEvent):*
function closePopup(flash.events::MouseEvent):*
function playerOptions(Object):*
function defaultTab():*
function tabCodeClickHandle(flash.events::MouseEvent):*
function update(Object):*
function acceptProfile(flash.events::MouseEvent):*
function getGift(flash.events::MouseEvent):*
I've tried so many way but cannot call any methods, even casting it to MovieClip.But in another project, i've used exactly this code and it worked!I've read many topic but cannot find out how.
Is there any solution for my problem! Thanks!

Clicking, pasting text and uploading files from extension

So I'm basically developing an automated click-paste-and-upload system for mutiple texts and files inside a google page.
This method helped me get the instances of objects that I'm looking for: buttons, textboxes, richtextboxes, etc.
Now I want to work with them.
So for example I know the id of a button , and the function subscribed to its click event. How do I trigger the click event from the extension ? I've tried injecting a script with the click event handler (discovered with DOM inspector) at "document_startup" but I don't get an error or anything else.
Here's the content script! The loggerhead function should have inserted the script but I don't think it did. What might be the reason for the blow code not giving anything?
// Runs a function for every added DOM element that matches a filter
// filter -- either function(DOM_node){/*...*/}, returns true or false
// OR a jQuery selector
// callback -- function(DOM_node){/*...*/}
function watchNodes(filter, callback){
observer = new MutationObserver( function (mutations) {
mutations.forEach( function (mutation){
if(typeof filter === "function"){
$(mutation.addedNodes).filter(
function(i){ return filter(this); }
).each(
function(i){ callback(this); }
);
} else {
$(mutation.addedNodes).filter(filter).each(
function(i){ callback(this); }
);
}
});
});
// For every added element, a mutation will be processed
// with mutation.taget == parent
// and mutation.addedNodes containing the added element
observer.observe(document, { subtree: true, childList: true });
}
function loggerhead(node) {
console.log("passhead");
//also inject jquery
var jqueryEl = document.createElement('script');
jqueryEl.setAttribute('src', chrome.extension.getURL('jquery-1.11.1.min.js'));
jqueryEl.setAttribute('type', 'text/javascript');
var scriptEl = document.createElement('script');
scriptEl.setAttribute('src', chrome.extension.getURL('script.js'));
scriptEl.setAttribute('type', 'text/javascript');
node.appendChild(jqueryEl);
node.appendChild(scriptEl);
}
watchNodes("head", loggerhead);
// method not working
//var gmailHead = jQuery("head", document).get(0);
script.js contains the function of subscribed to the click event of the button that I've managed to find through the DOM inspector:
function Cdb(b){return function(){if(Vbb()){return Ddb(b,this,arguments)}else{var a=Ddb(b,this,arguments);a!=null&&(a=a.val);return a}}}
You should try to call the existing click handler like
buttonElement.click()

AS3 add callbacks for listeners

lately I've been asked to change a small flash app i made to work with external callbacks instead of using the embedded buttons.
I tried to automate the process and came up with this function:
/**
* Add an External callback for all PUBLIC methods that listen to 'listenerType' in 'listenersHolder'.
* #param listenersHolder - the class that holds the listeners we want to expose.
* #param listenerType - a String with the name of the event type we want to replace with the external callback.
*/
public static function addCallbacksForListeners(listenersHolder:*, listenerType:String):void
{
// get the holder description
var description:XML = describeType(listenersHolder);
// go over the methods
for each(var methodXML:XML in description..method)
{
// go over the methods parameters
for each(var parameterXML:XML in methodXML..parameter)
{
// look for the requested listener type
var parameterType:String = parameterXML.#type;
if (parameterType.indexOf(listenerType) > -1)
{
var methodName:String = methodXML.#name;
trace("Found: " + methodName);
// get the actual method
var method:Function = listenersHolder[methodName];
// add the callback
try
{
ExternalInterface.addCallback(methodName, method);
trace("A new callback was added for " + methodName);
}
catch (err:Error)
{
trace("Error adding callback for " + methodName);
trace(err.message);
}
}
}
}
before using this function I had to change the listener's function to Public, add null default parameter and of course remove/hide the visuals.
for example, from :
private function onB1Click(e:MouseEvent):void
to :
public function onB1Click(e:MouseEvent = null):void
add this line to the init/onAddedToStage function:
addCallbacksForListeners(this, "MouseEvent");
and remove the button from stage or just comment the line that adds it.
My question is: can you find a better/ more efficient way to do that ?
any feedback is welcomed..
Maybe you should make the javascript to call a single method with different functionName param. Then you only need to add one callback and you don't need to make all those functions public.
ExternalInterface.addCallback('callback', onCallback);
public function onCallback(res:Object)
{
var functionName:String = res.functionName;
this[functionName]();
}

in mootools: calling a function after all events on an element is finished

i have this element to which various change events are applied
how can i trigger my own function after all change events have occurred in mootools
a sample scenario is a drop down list
$('ddl').addEvent('change', function () {
// some ajax call going on here and which i can't affect
// as the page is generated that way
});
i now want to call my function right after the change event is done but adding another change event will not do as i believe the events are executed async
pass on a callback function through the onComplete of the ajax that you reference.
eg:
$("ddl").addEvents({
change: function() {
new Request({
method: "get",
url: "somefile.php",
onComplete: function() {
// run your next stuff from within here, referencing
// this.response.text or whatevever and call up another function.
}
}).send("action=checkuser&id="+this.get("value").trim());
}
});
there's also the Chain class - http://mootools.net/docs/core/Class/Class.Extras#Chain but as you have async stuff going on, you really need the onComplete on the Request.