the page always alert "btn2" ,whenever I click btn1 or btn2. it's seem the problem caused the "click" closures.but I don't know how to fixed it.
thanks in advance.
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>untitled</title>
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
(function(){
$.fn.test = function(){
F.init.apply(this,arguments)
};
var F ={
that:null,
init:function(){
F.that = this;
$(F.that).click(function(e) {
F.method();
});
},
method:function(){
var text =$(F.that).html();
alert(text);
}
}
})();
$(function(){
$("#btn1").test(); //alert btn2---bug
$("#btn2").test(); //alert btn2
});
</script>
</head>
<body>
<button id="btn1">btn1</button>
<button id="btn2">btn2</button>
</body>
</html>
You have referred to your object class F by that name from within the class.
Your line F.that = this is effectively therefore creating what would in other OO languages be considered a "static member" of the class, so both #btn2 and #btn1 ended up sharing the same that member.
Furthermore, your click handler is trying to call F.method() - in effect also a static method call.
You'll need to create a new object of type F each time you wish to wrap it around an element. Only then will you get a separate this for each element.
I suggest using an off-the-shelf jQuery plugin model such as http://jqueryboilerplate.com/ instead of trying to invent your own. See this extract from that code:
$.fn[ pluginName ] = function ( options ) {
return this.each(function() {
if ( !$.data( this, "plugin_" + pluginName ) ) {
$.data( this, "plugin_" + pluginName, new Plugin( this, options ) );
}
});
};
Note how it uses new Plugin to create the plugin instance, and then stores it on the element using $.data, but only the first time the plugin is invoked against each element.
1)F is a static Object
2)So F.that is also static
3)so
F.that = this
line will set 'this' to F.that.
4)first time you call
$("#btn1").test();
then F.that will be equal to $("#btn1");//this will be equal to $("#btn1")
5)Next time you call
$("#btn2").test();
then F.that will be equal to $("#btn2");//this will be equal to $("#btn2")
6) So finally to F.that you are setting $("#btn2")
7)hence the $(F.that).html(); is essentially $($("#btn2").html()) which is further same as $("#btn2").html()
8)Hence alert is showing "btn2"
Related
I have a file call text.js and it has
var Text = function(canvas){
var textField = $('#textField'),
addTextButton = $('#addText');
var init = function(){
addTextButton.click(function(){
alert('won"t work?')
});
},
resetTextField = function(){
// it work if I put the selector here like var textField = $('#textField'),
textField.val(''); // won't work
};
return{
init:init
}
}();
It's included in my index.html. In there I do init like
$(function(){
Text.init();
}());
The problem is the even't can't be fired. I think I messed up something.
The code in Text is run immediately, and returns the object with init on it. If you run that code before the elements it looks up exist, for instance:
<!doctype html>
<html>
<head>
<!-- ... --->
<script src="text.js"></script><!-- Problem here -->
<script>
$(function(){
Text.init();
}());
</script>
</head>
<body>
<!-- ... --->
<input id="textField"><input id="addText" type="button" value="Add">
<!-- ... -->
</body>
</html>
... you'll end up with empty jQuery objects in textField and addTextButton.
Separately, you're also running the function you're trying to pass ready immediately (and then passing undefined into ready), the problem is here:
$(function(){
Text.init();
}());
// ^^---------- problem
You don't want those (). You want to pass the function into ready:
$(function(){
Text.init();
}); // <== Note no ()
If you're going to have the init method, it would be best to put all your initialization inside it rather than putting it in two places:
var Text = function(canvas){
var textField, addTextButton;
var init = function(){
textField = $('#textField');
addTextButton = $('#addText');
addTextButton.click(function(){
alert('won"t work?')
});
},
resetTextField = function(){
// it work if I put the selector here like var textField = $('#textField'),
textField.val(''); // won't work
};
return{
init:init
}
}();
Note, though, that if you follow the usual best practice of putting your scripts at the end of the document, just prior to the closing </body> tag, the elements defined above that will exist and be available, which would make using ready (and init) unnecessary. So if you control where the script tags go, that's an option.
So for instance:
<!doctype html>
<html>
<head>
<!-- ... --->
</head>
<body>
<!-- ... -->
<input id="textField"><input id="addText" type="button" value="Add">
<!-- ... -->
<script src="text.js"></script>
<script>
$(function(){
Text.init();
});
</script>
</body>
</html>
You are invoking the function once defined using () at a point where DOM is not loaded. Thus, all selectors return zero nodes.
var Text = function(canvas){
// ...
}();
^^
Remove that. And when you call it, you need to instance the function first, and keep that instance reference (if you wish to).
var text = new Text();
text.init();
I would like to make something like this:
function alrtHtml() {
alert(this.innerHTML)
}
function myFunc(id) {
document.getElementById(id).alrtHtml()
}
<html>
<head>
<meta charset="UTF-8" />
<title>test</title>
</head>
<body>
<h1 id="h1">Hello world!</h1>
<input type="button" value="click" onclick="myFunc('h1')" >
</body>
</html>
The result should be an alert with the text "Hello world!" inside the h1 tag.
It is my goal to be able to do this without explicitly passing the element as an argument to alertHtml.
You generally don't want to extend native prototypes, and one way to create chainable methods without doing that, is to create your own method to get the elements, and then create another chainable method to alert the innerHTML, like most libraries do.
Probably the simplest example would be something like this
function getElement(selector) {
if (!(this instanceof getElement)) return new getElement(selector);
this.element = document.querySelector(selector);
return this;
}
getElement.prototype.alertHtml = function() {
alert(this.element.innerHTML);
return this;
}
function myFunc(id) {
getElement(id).alertHtml();
}
myFunc('#test');
<div id="test">TEST</div>
This way you're only extending your own objects, not native objects, and you can create any kind of chainable method to add to that.
What you're looking to do is add your function to the prototype of whatever type document.getElementById(id) returns.
In this case it's returning an Element, so in order to add your function to its prototype you would write the following code.
Element.prototype.alrtHtml = function() {
alert(this.innerHTML)
}
As another alternative, you could also pass the element right to alertHTML:
function alertHTML(el) {
alert(el.innerHTML)
}
function myFunc(id) {
var elArg = document.getElementById(id)
alertHTML(elArg)
// You could also write it like this:
/*
alertHTML(document.getElementById('h1'))
*/
}
<h1 id='h1'>Hello, world</h1>
<button onclick="myFunc('h1')">Button</button>
There's a plethora of reasons to do that, but the gist of it is to avoid having issues if somebody else creates a alertHTML method on the Element prototype.
EDIT: If you really want to use this, you might also like to learn about binding functions - funfunfunction made a good video on this here. Here's how that would work:
function alertHTML() {
alert(this.innerHTML)
}
function myFunc(id) {
var el = document.getElementById(id)
alertHTML.apply(el)
}
<h1 id='h1'>Hello, world</h1>
<button onclick="myFunc('h1')">Button</button>
apply runs whatever its function is with this as the first argument you pass to apply. (The rest of the arguments you pass to apply are passed directly to the function.)
I have an AgentClass with the method this.move. It's working with static objects but when I create new HTML Objects via .append(), I can't use them with my this.move method.
All the new objects have an ID and I want to animate them with the move method.
I often read "live, on, ..." but they all need an event... I don't have such an event on them. They move directly. I tried something like that:
$('.agents').on("load", Agent.move());
But that isn't working... Any ideas?
Codesinppet:
var Agent = function(agentType, xTarget, yTarget) {
...
this.move = function() {
var id = this.agentId;
$('.agent#'+id).animate({
left:"200px"
}, 1000);
}
}
And I append them after this like this:
for (deployed = 0; deployed <= agents; deployed++) {
$('.agents').append('<div class="agent" id="'+deployed+'"></div>');
}
It would be awesome if someone could help me!?
You can use .clone(true)
A Boolean indicating whether event handlers and data should be copied along with the elements. The default value is false.
var agents = 6;
for (deployed = 0; deployed <= agents; deployed++) {
$element = $('<div class="agent" id="'+deployed+'"></div>').clone(true);
$('.agents').append($element);
}
.agent {
height:50px;
width:50px;
background-color:yellow;
margin-bottom:10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>Agent</title>
</head>
<body>
<div class="agents">
</div>
</body>
</html>
But for maximum optimization event is better to use an event handler "on" to monitor the items that will be added after reloading the DOM .
This allocates less memory
I have html buttons "classA","classB" and "classC" to which I assign the onclick handler function as follows..
var classA = document.getElementById('classA');
classA.onclick = filterByClassA;
var classB = document.getElementById('classB');
classB.onclick = filterByClassB;
var classC = document.getElementById('classC');
classC.onclick = filterByClassC;
These 3 functions do the same thing, only difference being the class.
So, can I have a single function assigned to these buttons, called with different parameters for each button. Something like below
var classA = document.getElementById('classA');
classA.onclick = filterByClass('classA');
var classB = document.getElementById('classB');
classB.onclick = filterByClass('classB');
var classC = document.getElementById('classC');
classC.onclick = filterByClass('classC');
I know this is a function call and not assignment and this is wrong but is there a way I can achieve this i.e. assign a function and pass parameter at the same time but not call it?
function filterByClass(className)
{
return function()
{
// Do something with className
console.log(className);
}
}
Bind can help you out here: Its called partial application.
Bind Syntax
fun.bind(thisArg[, arg1[, arg2[, ...]]])
1st param is scope of the function when it is called.
From 2nd you can pass any number of agruments. See the below code to know how it works.
Code:
var classA = document.getElementById('classA');
classA.onclick = filterByClass.bind(classA, 'classA');
var classB = document.getElementById('classB');
classB.onclick = filterByClass.bind(classB, 'classB');
var classC = document.getElementById('classC');
classC.onclick = filterByClass.bind(classC, 'classC');
function filterByClass(className, eventObject) {
console.log(this, className, eventObject);
}
Update:
Check out the Compatibility section in the above MDN link. You may need to use it, if you are going to use bind in non modern browsers.
i always try to keep the code as short as possible
so if your buttons are inside a container you can do that.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>atest</title>
<script>
window.onload=function(){
var c=document.getElementsByTagName('div')[0].childNodes,
l=c.length,
filterByClass=function(){
console.log(this.id);//this.id is the classA or whatever
};
while(l--){
c[l].onclick=filterByClass;
}
}
</script>
</head>
<body>
<div>
<button id="classA">A</button>
<button id="classB">B</button>
<button id="classC">C</button>
</div>
</body>
</html>
in this case
document.getElementsByTagName('div')[0]
returns the first div in the document
childNodes
give u the list of the buttons inside that div
the while function adds the onclick event with your function 'filterByClass'
inside filterByClass u can access the element by this and so return it's id with this.id
all.
I'm having a hard time figuring this out, it's the second time I need to do something with tinyMCE but this time I just can't find the answer.
Here's what I want to do: I have added a button on my editor that opens a new popup with a single text input field and a button. I want to click the button and grab the value I set in my input field, then use that value to modify what I have in my editor.
Here's what I have so far - only relevant code:
init : function( ed, url ) {
ed.addCommand( 'mceTooltip', function() {
ed.windowManager.open({
file: 'imageurl.html',
width: 480,
height: 180,
inline: 1,
title: 'Please enter an image URL'
}, {});
});
}
This is what imageurl.html has:
<input type="text" id="image-url" />
<input type="button" id="submit-image-url" value="Ok" />
So, what I need to do is get whatever "image-url" text input has whenever I click the OK button, and use that text inside my editor. I know I can use ed.selection.setContent( fieldValue ) and it will replace my selected text with the image-url value, I just don't know how to get the image-url value.
The most detailed info I was able to find was http://www.tinymce.com/wiki.php/How-to_implement_a_custom_file_browser but I can't make it work for my needs.
Anybody who can help me out with this? I'm sure it should be simple for somebody with more experience on this.
Thank you all for your attention.
Updated imageurl.html **
<script>
document.getElementById( 'submit-image-url' ).onclick = function(){
var imageUrl = document.getElementById( 'image-url' ).value;
window.parent.tinyMCE.activeEditor.execCommand( 'mceInsertContent', 0, imageUrl );
window.parent.tinyMCEPopup.close(); // this line gets me this error: "Uncaught TypeError: Cannot read property 'windowManager' of undefined "
};
</script>
Ok, this shouldn't be that difficult.
issue this in a script-tag on bottom of your imageurl.html or use a document ready javascript function. The following will add an onclick handler to your button which will get the image_url and write this to the tinymces selection.
$('#submit-image-url').bind('click', function(){
var image_url = $('#image-url').val();
// in case you are using a real popup window
window.opener.tinymce.activeEditor.selection.setContent(image_url);
// in case you use a modal dialog
tinymce.activeEditor.selection.setContent(image_url);
});
You have opened up a window so you are currently in IFrame having imageurl.html ok..
what you have to do is
on a parent page create one variable of global type like
var image_url = "";
now on imageurl page create a script on body part like this
<body>
<script>
$("#button").click(function(){
window.parent.image_url = $('image-url').val();
});
</script>
</body>
make sure you have jquery on imgurl. or otherwise use addeventlistener or attachevent
method
logic is get parent window's element from the iframe and save it from iframe.
Ok, I found the problem. I had to include tiny_mce_popup.js inside imageurl.html, that's why the tinyMCEPopup.close() didn't work:
<script type="text/javascript" src="js/tinymce/tiny_mce_popup.js"></script>
<script>
document.getElementById( 'submit-image-url' ).onclick = function(){
var imageUrl = document.getElementById( 'image-url' ).value;
tinyMCEPopup.execCommand( 'mceInsertContent', 0, imageUrl );
tinyMCEPopup.close();
};
</script>
I wrongly assumed it was being loaded because I was able to see the popup.
Originally I didn't want to modify imageurl.html, but it looks like that's just the way it has to be done...
Anyway, I already knew how I could address some of these tasks from inside imageurl.html file, and I had already seen tinyMCEPopup had a close() method, but to keep it fair, I'll accept the answer from the person who I felt was more active in trying to help me out.
Thanks everyone.
Final code will like this.working ...
imageurl.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="tiny_mce_popup.js"></script>
</head>
<body>
<input type="text" id="image-url" />
<input type="button" id="submit-image-url" value="Ok" />
<script>
document.getElementById( 'submit-image-url' ).onclick = function(){
var imageUrl = document.getElementById( 'image-url' ).value;
tinyMCEPopup.execCommand( 'mceInsertContent', 0, imageUrl );
tinyMCEPopup.close();
};
</script>
</body>
</html>