What I have is kinda unusual I guess. I have this function deleteItem which is triggered onclick and has the following parameters
function dItem(type,id,element,confirmed){
if(confirmed){
handle delete function
}else{
var c = ',';
popup('Are you sure you want to delete this item?',
{
"Yes":"dItem('"+type+"'"+c+id+c+element+c+true+")",
"Cancel":"popupClose()"
}
)
}
}
.. onclick='dItem("comment",15,this,false)' ..
In popup()'s second parameter are passed the buttons that are to be displayed in the popup and the functions they call respectively. The problem is that element is a HTMLDIV element and I cannot figure out a neat way to pass that through a string. The only solution I could come to think of is to have a global variable holding the element in question and not passing it at all, although I don't really want to do that since it's more of a hack rather than a solution. Does anybody have any idea how I can pass that element through a string? Thanks in advance!
EDIT:
This is how the buttons object b is being processed and turned into HTML. Do you see how I can supply it with an actual function instead of just a name in the form of string?
var _b = '';
for(var i in b){
_b+="<div onclick='"+b[i]+"'>"+i+"</div>";
}
It's more common to handle this situation with callbacks. You will need to alter your popup function for that to work.
Example:
popup('Are you sure you want to delete this item?', {
"Yes": function () {
dItem(type, id, element, confirmed);
},
"Cancel": function () {
popupClose();
}
});
As a workaround you could simply generate an unique ID for the element and use that to identify the element later on. Because your function is recursive you need to deal with the fact that element can be either a ELEMENT_NODE or a string.
for(var i in b){
var generatedId = i /* TODO: not sure this generates an unique id */;
_b += "<div id='" + generatedId + "' onclick='" + b[i] + "'>" + i + "</div>";
}
function dItem (type, id, element, confirmed) {
if (confirmed) {
// handle delete function
}else{
var elementId;
// find the elementId
if (element && element.nodeType && element.nodeType == 1) {
elementId = element.id;
}else if (typeof element == 'string') {
elementId = element
}else{
throw Error('Argument [element] is not a ELEMENT_NODE or string');
}
var args = [type, id, elementId, true];
popup('Are you sure you want to delete this item?', {
"Yes": "dItem(" + args.join(', ') + ")",
"Cancel": "popupClose()"
});
}
}
Related
Note: The suggested question is not exactly a duplicate, but one of the answers in there does provide a solution.
My annotated code is as follows:
function AddMedRow(brand, generic, dose, doseunits, freq, durn, durnunit, instrn) {
$(".DrugRow").each(function () {
id = $(this).attr('id');
count = Number(id.replace("DrugRow", ""))
// If this row is empty, can add here
if ($("#brand" + count).val() == "" && $("#generic" + count).val() == "") {
$("#brand" + count).val(brand)
// I actually want to return true and break out of AddMedRow
return true
}
});
// Some other code continues here, but should not execute once the if block in .each is true
}
Edit: I checked with the following code:
function AddMedRow(brand, generic, dose, doseunits, freq, durn, durnunit, instrn) {
dontiterate = false
$(".DrugRow").each(function () {
id = $(this).attr('id');
console.log("id is " + id);
// If this row is empty, can add here
count = id.replace("DrugRow", "");
count = Number(count)
if ($("#brand" + count).val() == "" && $("#generic" + count).val() == "") {
$("#brand" + count).val(brand)
dontiterate = true
console.log("Let's see if we can break out without a control variable")
return false
}
});
if (dontiterate) {
console.log("Not iterating because we are checking a control variable.")
return true
}
}
The result:
id is DrugRow1
Let's see if we can break out without a control variable
Not iterating because we are checking a control variable.
That means returning true or false from within .each doesnt do anything. You need to use a control variable or flag
I have a very simple problem and keep finding answers to similar questions with more complexity. I am trying to replace image links in loaded html and decided that the best is to read the html into a string variable loadedHTML using .get(), like this:
$.get(loadURL, function(loadedHTML) {
myFunction(loadedHTML);
}, 'html');
In myFunction, I want to make some changes to the loaded html and eventually return it. I can't get .find() to work. Here is what that code looks like:
function myFunction( html ) {
var $html = $("<div>" + html + "</div>");
console.log( "$html.html() = " + $html.html()); // works!
$html.find("img", function() {
console.log("found an image"); // doesn't work :(
});
}
I am killing myself with something that is probably really simply. Let me know how I am dumb please...
I'm almost sure that you cannot use find in the way that you have.
Try something like:
var $foundImages = $html.find("img");
console.log($foundImages.length);
Which would, in theory, output the number of images that were found.
The find method doesn't have a second parameter:
http://api.jquery.com/find/
You should try this:
function myFunction( html ) {
var $html = $("<div>" + html + "</div>");
console.log( "$html.html() = " + $html.html()); // works!
console.log($html.find("img"));
}
Simply assign id to your div tag .
like below,
var $html = $("<div id='placeholder'>" + html + "</div>");
and find img with it like below,
$("#placeholder").find("img", function() {
console.log("found an image"); // doesn't work :(
});
your resultant code,
function myFunction( html ) {
var $html = $("<div id='placeholder'>" + html + "</div>");
console.log( "$html.html() = " + $html.html()); // works!
$("#placeholder").find("img", function() {
console.log("found an image"); // doesn't work :(
});
}
.find() didn't have callback function in jquery. it have parameter for selectors,elements,jqueryObject only.you have to check with length or condition like this
if($html.find("img").length > 0){
// do stuff here
}
or
if($html.has("img")){
// do stuff here
}
You can use this .filter():
var found = $html.find("img").filter(function() {
return this;
});
console.log(found);
or make an array out of it with .map():
var found = $html.find("img").map(function() {
return this;
}).get(); // use get() method here to get the values in array
console.log(found.length); // would give you the length of array created.
jQuery.find() doesn't have a callback but you can extend jQuery to do what you want:
jQuery.fn.extend({
findEach: function (selector, callback) {
var found = this.find(selector);
if (typeof callback == 'function' && found.length > 0) {
found.each(callback);
}
return found;
}
});
Then use like you expect:
$html.findEach("img", function(key, value) {//will run for each image
console.log(key);
console.log(value);
console.log(this);
});
Question
I'd like to know the best way I can wrap the jQuery function while retaining all functionality. Essentially I want to call $('#someId') but have it operate as $('#' + id + 'someId') by wrapping the function, modifying the arguments, and passing it through to the original jQuery function.
Motivation
I have a section of JS that will reuse the same variable winId which is concatenated and passed to jQuery. Instead of writing
$('#' + winId + 'someId').html();
$('#' + winId + 'someOtherId').css();
...
$('#' + winId + 'someThirdId').text();
throughout the whole file, I want to wrap the jQuery function so I can just call
$('#someId').html();
$('#someOtherId').css();
...
$('#someThirdId').text();
and and have winId added in before passing through to $.
My attempt
Here's what I'm thinking as a wrapper:
(function() {
var fn = $;
return $ = function() {
for ( var i = 0; i < arguments.length; i++ ) {
if ( typeof arguments[i] == 'string') {
arguments[i] = /* code to add in winId, omitted */
}
}
return fn.apply( this, arguments );
}
})();
This works great, except that obviously none of the methods like $.ajax are available:
Uncaught TypeError: Object function () {
for ( var i = 0; i < arguments.length; i++ ) {
if ( typeof arguments[i] == 'string' ) {
arguments[i] = /* code to add in winId, omitted */
}
}
return fn.apply( this, arguments );
} has no method 'ajax'
Note: I know I could copy the object over using jQuery.extend($, jQuery), but I'm interested in a more elegant solution than that if possible.
Here's a different implementation:
DEMO
(jQuery.fn.init = (function (init) {
return function (selector) {
if (typeof selector === 'string' && selector[0] === '#') {
arguments[0] = selector.replace('#', '#prefix_');
}
return init.apply(this, arguments);
};
})(jQuery.fn.init)).prototype = jQuery.fn;
$(function () {
console.log($('#test').length);
console.log($.ajax);
});
EDIT: Followup question: How can I apply this only within a closure? For example, within an object.
Perhaps with functions that allows to add named decorators and remove them, something like:
HTML
<div id="prefix_test"></div>
JS
var decJQ = (function (decJQ, $) {
var decorators = {},
init = $.fn.init;
($.fn.init = function () {
for (var k in decorators) {
if (decorators.hasOwnProperty(k)) {
arguments = decorators[k].apply(this, arguments);
}
}
return init.apply(this, arguments);
}).prototype = $.fn;
return $.extend(decJQ, {
decorate: function (name, fn) {
decorators[name] = fn;
},
undecorate: function (name) {
delete decorators[name];
}
});
})(window.decJQ || {}, jQuery);
decJQ.decorate('idPrefix', function (selector) {
if (typeof selector === 'string' && selector[0] === '#') {
arguments[0] = selector.replace('#', '#prefix_');
}
return arguments;
});
$(function () {
console.log($('#test').length); //1
decJQ.undecorate('idPrefix');
console.log($('#test').length); //0
});
EDIT 2:
You could also go for something extremely simple, such as:
(function ($) {
//use $ which has been wrapped
})(function () {
//do some manipulations
return jQuery.apply(this, arguments);
});
Following the suggestion by Bergi and the post he links to here, this is one way to go:
$.fn.extend({
initCore: $.fn.init,
init: function (selector, context, rootjQuery) {
if (typeof selector === 'string' && selector[0] === '#') {
selector = selector.replace('#', '#' + winId);
}
return $.fn.initCore(selector, context, rootjQuery);
}
});
$.fn.init.prototype = $.fn;
I've tested $('#foo') will find a div that has a winId prefixed to the id value, like this <div id="1foo"></div>.
For example: http://jsfiddle.net/MfdJS/1/
Add class="winID" to your elements.
Use $(".winID").find('#someId").css(...) to access CSS attributes of specific element.
Use $(".winID").css(...) to access CSS attribues to all winID tagged elements.
ok well i just tested
$('.con'+'tainer')
and
$('d'+'iv');
and
var s = 't';
$('.con'+s+'ainer');
and the console is returning the correct values
i belive that you are calling a function jQuery() with a string parameter, so as long as you use the normal syntax for building/appending/constructing a string with the plus signs, i think you're golden. im glad you asked this question because now i know too
That's a pretty strange thing to do. Why don't you just create a CSS selector string for winId and save it as a variable?
var foo = '#' + winId;
Now you can do:
$(foo + ', #bar').html("add some content");
What you're proposing to do will leave any programmer working on this project -- including you six months from now -- completely flummoxed when they use $('#bar') and it's actually selecting #foo and #bar.
I have a javascript function that accepts a function as a parameter. I want to determine the name of the function is passed. How is that possible with javascript?
Here is a code I have so far. $fnc == "SliderMoney" is working. It's always returning false.
function SliderCreate($id, $fnc) {
$lbl = "#" + $id + "_lbl";
$div = "#" + $id;
$slider = $($div).slider({
});
if ($fnc == "SliderMoney") {
UpdateDisplay($slider, $lbl, "$");
} else {
UpdateDisplay($slider, $lbl, "");
}
}
Thanks,
Susan
No you can't by default.
Perhaps you pass it an object or as a third parameter.
I am building a drag'n'drop gui builder in Javascript. So far so good.
As I add items to the GUI and configure them; I have two mechanisms for addressing them:
the 'class' - which I use for doing things to all instances of an item (eg CSS, generic functionality and so on and so forth) and which I can bind javascript libraries to... and I can make full use of polymorphic class names (ie class="name1 name2 name3 name4" with different things bound to each class name...)
the 'id' - which refers to this particular instance of a text box or a paragraph and which I can bind javascript libraries to
My problem is this: the 'id' must be unique across all html items on the page (by definition) so how do I ensure this? I need to get all the id's of all the items and then maintain some sort of state table.
Starting from a blank bit of html this is pretty reasonable - but I need to start from a partly created bit of html with a mixture of existing 'id's - some of which will be in my unique scheme and some of which wont be...
The way to do this best ought to be a solved problem.
Suggestions, tips, examples?
The best way to do this will depend entirely upon the structure and organization of your javascript. Assuming that you are using objects to represent each of your GUI elements you could use a static counter to increment your ids:
// Your element constructor
function GuiElement() {
this.id = GuiElement.getID();
}
GuiElement.counter = 0;
GuiElement.getID = function() { return 'element_' + GuiElement.counter++; };
Of course you probably have more than one type of element, so you could either set each of them up so that they have their own counter (e.g. form_1, form_2, label_1, label_2) or so that they all share a counter (e.g. element_1, element_2, element_3), but either way you will probably want them to inherit from some base object:
// Your base element constructor
function GuiElement(tagName, className) {
this.tagName = tagName;
this.className = className;
}
GuiElement.counter = 0;
GuiElement.getID = function() { return 'element_' + GuiElement.counter++; };
GuiElement.prototype.init = function() {
this.node = document.createElement(this.tagName);
this.node.id = this.id = GuiElement.getID();
this.node.className = this.className;
}
// An element constructor
function Form() {
this.init();
}
Form.prototype = new GuiElement('form', 'form gui-element');
// Another element constructor
function Paragraph() {
this.init();
}
Paragraph.prototype = new GuiElement('p', 'paragraph gui-element');
You could also go this route if you would rather keep some variables "private":
// Your element constructor constructor
var GuiElement = (function() {
var counter = 0;
function getID() {
return 'element_' + counter++;
}
return function GuiElement(tagName, className) {
return function() {
this.node = document.createElement(tagName);
this.node.id = this.id = getID();
this.node.className = className + ' gui-element';
this.className = className;
};
}
})();
// Create your element constructors
var Form = GuiElement('form', 'form'),
Paragraph = GuiElement('p', 'paragraph');
// Instantiate elements
var f1 = new Form(),
f2 = new Form(),
p1 = new Paragraph();
Update: If you need to verify that an id is not already in use then you could add the check you and of the getID methods:
var counter = 0;
function getID() {
var id = 'element_' + counter++;
while(document.getElementById(id)) id = 'element_' + counter++;
return id;
}
function uniqueId() {
return 'id_' + new Date().getTime();
}
If you happen to be using the Prototype library (or want to check it out), you can use the Element.identify() method.
Otherwise, Darin's response is a good idea as well.
function generateId() {
var chars = "0123456789abcdefghiklmnopqrstuvwxyz",
string_length = 8,
id = '';
for (var i = 0; i < string_length; i++) {
var rnum = Math.floor(Math.random() * chars.length);
id += chars.substring(rnum, rnum + 1);
}
return id;
}
Close enough to unique is good enough. Don't use the Date() solution unless you're only generating a single ID at any given time...