I'm trying to work with Raphael for some SVG stuff and tried, well, with my limited knowledge, to build something beautiful ;)
I have 3 files:
1x html file and 2xjs files
html file: with an onload function ( + header,body and stuff)
window.onload=function()
{
init();
}
js File1: has the init function and a function to load js files (e.g. Raphael) and a callback to proceed after the file is loaded
function init()
{
getScripts(initTool)
}
function getScripts(callback)
{
$.when($.getScript(scripts[raphael]).then(callback)
}
function initTool()
{
$('body').append("<div id='tool'></div>");
tool=Raphael("tool",5000,5000);
$('body').append("<a href='javascript:void(0)' onclick='newElement'>New element</a>")
}
js File2: Here I have the function newElement which should add (for this example) a single path to the svg element created by Rapahel
function newElement()
{
tool.path("M10,20L30,40");
}
Unfortunately the path does not show up and I have no idea why. I tried referencing the "tool" variable before the onload in case it it related to global/local variables (wild guessing) but this also does not work. changing id's to "tool" to "tool2" for the svg element also does not work.
What else could it be? Where is my (possibly obvious) blind spot?
SHould callback not be declared as a parameter here?
function getScripts(callback)
{
$.when($.getScript(scripts[raphael]).then(callback)
}
To be honest with you I've written quite a bit of javascript and I don't quite grok variables scopes fully yet. However, when calling functions you should use parenthesis to indicate that it should be executed (there are a couple of times when you reference them without parenthesis, but that is beyond the scope of this answer).
So...
$('body').append("<a href='javascript:void(0)' onclick='newElement()'>New element</a>")
But this isn't enough to make it work, you should also declare your function like this:
var newElement = function() {
tool.path("M10,20L30,40");
}
Here is a working solution: http://jsfiddle.net/vAjG2/
(perhaps somebody can expand on why these changes are needed, I don't grasp them myself).
The problem has nothing to do with variable scope. You just need parentheses following the function name in your inline event handler. Rewrite the last line as:
$('body').append("New element")
and you'll be up and running.
However, inline event handlers are frowned upon for a whole variety of reasons. As quirksmode says: "Although the inline event registration model is ancient and reliable, it has one serious drawback. It requires you to write JavaScript behavior code in your XHTML structure layer, where it doesn't belong."
A much cleaner way to do this would separate out the markup and the script, e.g.:
<div id='tool'></div>
<a id="mylink" href='#'>New element</a>
<script>
var tool = Raphael("tool",500,500);
$('#mylink').on("click", function() {
tool.path("M10,20L30,40");
});
</script>
See this jsfiddle for this code in action.
Lastly, as a helpful hint, I would advise running your code on document ready, instead of window load, especially you're using jquery,. Document ready happens when the DOM is first constructed. Window load waits for all assets to be fully loaded, which can take awhile, and typically isn't necessary. It's long considered a best practice.
Related
(new to JS, jQuery, & jqTree)
I am trying to override a method (JqTreeWidget.prototype.openNode) from one .js file (tree.jquery.js) in another (my own custom.js).
I've read that to override a js method in general, I just need to redefine it. So I am trying to do that on the method, and I think I am stuck on accessing the variable that has the original method (JqTreeWidget). I think the challenge is that the original method is in tree.jquery.js (source) that is separate from my own other custom.js file where I want to do the override.
The goal of this Question would be to allow me to write something like this in my custom.js (<reference to JqTreeWidget.prototype.openNode> would be the Answer to this Question):
var originalMethod = <reference to JqTreeWidget.prototype.openNode>;
// Override of originalMethod
<reference to JqTreeWidget.prototype.openNode> = function( node, slide ){
// my code I want to happen 1st here
changeAncestorHeightRecursively( node, true);
// my code is done, and now I'm ready to call the original method
originalMethod.call( this, node, slide );
}
I think that would be the most non-intrusive way to do the override, without actually hacking in to the tree.jquery.js source.
See my custom.js at http://codepen.io/cellepo/pen/LGoaQx
The separate source tree.jquery.js is added externally in the JS settings of that codepen.
How can I get access (from within my custom.js file) to JqTreeWidget variable that is in the source file (tree.jquery.js)? Is it even possible? Is JqTreeWidget not in scope outside of tree.jquery.js, or is it not a global variable? I was hoping treeContainer.tree.prototype would have it, but I haven't had luck so far...
Thanks!
The prototype object can be obtained via:
jQuery.fn.tree("get_widget_class").prototype
Note that this is not a generalized solution for any jQuery plugin. This is something explicitly implemented by the tree plugin.
I found this hacky workaround. But since it's a hack, I'd still prefer to find the Answer as posed in this Question (so please, continue to Answer with respect to the <reference to JqTreeWidget.prototype.openNode> I mentioned in the Question, thanks)...
As stated in this Question, the goal involves making it possible to override JqTreeWidget.prototype.openNode (from tree.jquery.js) externally in custom.js. As such, calls to changeAncestorHeightRecursively (my code) & JqTreeWidget.prototype.openNode would both be made from the override in custom.js, and tree.jquery.js source is not modified at all.
Workaround:
Declare global var in html:
<script type='text/javascript' language="javascript">
changeAncestorHeightRecursively = 1;
</script>
In custom.js, set the globar var to the function (the one I want to be called before JqTreeWidget.prototype.openNode):
window.changeAncestorHeightRecursively = changeAncestorHeightRecursively;
Call the global-var-referenced function at the beginning of JqTreeWidget.prototype.openNode (hack into tree.jquery.js):
JqTreeWidget.prototype.openNode = function(node, slide) {
// Only way I could figure out to get this to execute before the rest of this method
// (global-var-referenced function in custom.js)
changeAncestorHeightRecursively( node, true );
// Rest of original openNode code...
}
This calls my code function from within tree.jquery.js, as opposed to calling the overridden method from within custom.js. So this is hacky because of the global var, and modifying tree.jquery.js source.
This will work for now, but hoping for a less hacky Solution as stated in this original Question... Thanks!
So here' s the piece of code. I'm very new to JavaScript so don't be afraid to explain the obvious
$(".my-css-class").on("click", function() {
($(this).attr("data-property-1"), $(this).attr("data-property-2"), this);
});
There's an element in the .jsp page that looks like this:
<i class="clickMe"></i>
I know the .jsp creates a link-icon, and that the above JavaScript is an event handler. I know that it passes these 3 values as arguments another JavaScript method:
function doStuff(prop1, prop2, obj) {
if (prop1 == 'foo') {
//do stuff with prop2
}
else{
// do stuff with obj
}
}
It all works fine. What I want to know is what exactly is going on to make it work? I can't find anything in the code that connects what the event-handler returns to the 'doStuff' java-script function.
The names are totally different, so it's not reflection, it can't be parameter matching because there's other functions with the same number and type of parameters in the file, it can't be convention based because it still works if I find/replace the name of the function to gibberish.
I guess basically I'm asking what this line is doing:
($(this).attr("data-property-1"), $(this).attr("data-property-2"), this);
tl;dr: I'm at a loss, I know how the properties get as far as the onClick event-handler's anonymous function - but how does JavaScript know to pass them as arguments the to the doStuff() function?
the onClick event is a standard event triggered on click of any clickable html element and is automatically raised by the DOM.
You are hooking in to this by listening on any matched ".my-css-class" elements for an onClick Event.
The jquery syntax ".on" has been simplified over time and allows you to hook into any number of events like "submit" - OnSubmit event , or "load" - onLoad Event
Wherever your on("click", myFunction) event hook is picked up, your myFunction will execute.
Looking at your second point...
because it still works if I find/replace the name of the function to gibberish.
The DoStuff function will be found and replaced across all files in your site? or page? or open tabs? , so therefore it must exist somewhere as "doStuff(" or "giberish(".
so when you do a global find/replace, do each one slowly, until you locate it.
Finally, when you do a view source in the browser, this should either explicitly show you the doStuff function, or at the very least give you a clue as to satelite files loaded at runtime, where you can go and investigate.
Use firebug in firefox to debug loaded resources; the ".net tab" to view external loaded resources and the html/javascript they might contain. (for example: your master page might be loading in an embeded resource that contains the doStuff method, becuase of a user or server control reference in that master page)
Also have a look at this:
http://www.developerfusion.com/article/139949/debugging-javascript-with-firebug/
You can step through the javascipt piece by peice until it hits the doStuff method.
Just remember to set at least 1 breakpoint ;-)
I'm starting to work with NodeJS, and more expecifically with MEAN.JS. I'm trying to run some custom JS code, using JQuery, but no matter where i put the code, it nevers runs as expected. This is my script:
$(document).ready(function(){
var tooltips = $('[data-toggle="tooltip"]');
tooltips.tooltip();
});
I tried putting it in the body of the page, in a separate script, but nothing. When I debug in Chrome, the variable tooltips does not contain any elements, but if I execute the same code in Chrome's console, then it works. It seems to me that despite the $(document).ready() thing, the DOM is not ready when the code executes. Maybe AngularJS is doing its magic at the same time and that interferes.
Is there somethign i need to do so that the code will get executed? Do I have to load it after/before something?
Thanks for any help.
I would suggest creating a directive instead of applying it in a dom ready:
angular.module("myModule")
.directive('tooltip', function () {
return {
restrict: 'A',
link: function (scope, elem) {
$(elem).tooltip();
}
}
});
Now, any time you use the tooltip or data-tooltip attribute on an element in one of your templates, the tooltip plugin will be applied to it.
Disclaimer: i have not tested this code, and in the end would suggest not using jquery for this. Instead, use angular-bootstrap-tooltip or a similar angular solution
Tooltips will not contains any elements as it is limited to the scope of the anonymous function you specified for $(document).ready(). Second, "tooltips" is misspelled in the variable declaration. Try this code to help you debug:
$(document).ready(function(){
window.$tooltips = $('[data-toggle="tooltip"]');
$tooltips.tooltip();
});
Now you can go into the console and evaluate the variable $tooltips to see if it is there. Note: I prefixed the variable with a $ to help identify it as a jQuery object. Don't confuse it with the built-in Angular services.
Also, Angular will not execute JavaScript within templates it generates pages from. Be sure to specify external JavaScript in the main page output or place this code to be executed when Angular loads the view.
So, as a sort of exercise for myself, I'm writing a little async script loader utility (think require.js, head.js, yepnope.js), and have run across a little bit of a conundrum. First, the basic syntax is like this:
using("Models/SomeModel", function() {
//callback when all dependencies loaded
});
Now, I want to know, when this call is made, what file I'm in. I could do it with an ajax call, so that I can mark a flag after the content loads, but before I eval it to mark that all using calls are going to be for a specific file, then unset the flag immediately after the eval (I know eval is evil, but in this case it's javascript in the first place, not json, so it's not AS evil). I'm pretty sure this would get what I need, however I would prefer to do this with a script tag for a few reasons:
It's semantically more correct
Easier to find scripts for debugging (unique file names are much easier to look through than anonymous script blocks and debugger statements)
Cross-domain requests. I know I could try to use XDomainRequest, but most servers aren't going to be set up for that, and I want the ability to reference external scripts on CDN's.
I tried something that almost got me what I needed. I keep a list of every time using is called. When one of the scripts loads, I take any of those using references and incorporate them into the correct object for the file that just loaded, and clear the global list. This actually seems to work alright in Firefox and Chrome, but fails in IE because the load events seem to go off at weird times (a jQuery reference swallowed a reference to another type and ended up showing it as a dependency). I thought I could latch on to the "interactive" readystate, but it doesn't appear to ever happen.
So now I come asking if anybody here has any thoughts on this. If y'all want, I can post the code, but it's still very messy and probably hard to read.
Edit: Additional usages
//aliasing and multiple dependencies
using.alias("ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js", "jQuery");
using(["jQuery", "Models/SomeModel"], function() {
//should run after both jQuery and SomeModel have been loaded and run
});
//css and conditionals (using some non-existant variables here)
using.css({ src: "IEFix", conditionally: browser === "MSIE" && version < 9 });
//should include the IEFix.css file if the browser is IE8 or below
and to expound more on my response below, consider this to be file A (and consider the jquery alias from before to be there still):
using(["jQuery", "B"], function() {
console.log("This should be last (after both jQuery and B have loaded)");
console.log(typeof($));
});
Then this would be B:
using("C", function() {
console.log("This should be second");
});
And finally, C:
console.log("This should be first");
The output should be:
This should be first
This should be second
This should be last (after both jQuery and B have loaded)
[Object Object]
Commendable that you are taking on such an educational project.
However, you won't be able to pull it off quite the way you want to do it.
The good news is:
No need to know what file you are in
No need to mess with eval.
You actually have everything you need right there: A function reference. A callback, if you will.
A rough P-code for your using function would be:
function using(modules, callback) {
var loadedModules = []
// This will be an ajax call to load things, several different ways to do it..
loadedModules[0] = loadModule(modules[0]);
loadedModules[1] = loadModule(modules[1]);
// Great, now we have all the modules
// null = value for `this`
callback.apply(null, loadedModules);
}
I have a .htc file whose behaviour is attached to a div in my page (div#test). Within the file, there is a tag at the top, setting up the behaviour:
<PUBLIC:ATTACH EVENT="ondocumentready" FOR="element" ONEVENT="function1()" />
And throughout the file, there are calls to 'element', & this.element - which I presume are then referring to this div#test.
If I wanted to take the JS from this file, would it be possible to put into the main .html page? I've tried to make calls to the function on document load, but can't get my syntax correct.
I'm trying:
document.getElementById.('test').attachEvent(onlonad, function1());
Would appreciate any pointers, if I'm doing something basic wrong, or if anyone can tell me why doing it at all would be a bad idea! =)
You have a dot in the wrong place, you're passing an undefined variable to the function and you're calling function1() instead of passing it:
document.getElementById.('test').attachEvent(onlonad, function1());
// ^ this ^ ^ ^ and these ^^
Correct syntax would be
document.getElementById('test').attachEvent("onload", function1);
Also note that only a few elements support the onload event - images, scripts and the body (which maps to window.onload).
If you want to make calls on document load, then it's awkward in IE because it doesn't support the document ready event that other browsers support. There are ways around this, or you can use the window.onload event:
window.onload = function () {
// Code to execute when the window is loaded here
}