Replacing widget element with a newly constructed DOM structure - javascript

<script>
(function( $ ) {
$.widget( "my.dropbox", {
errorText: function(text) {
$(this.element).next().html(text);
},
_create: function() {
var id = $(this.element).attr("id");
var customDropbox = $(
"<div class='form-group'>"+
"<label for='"+id+"'>"+getLabelFor(id)+"</label>"+
"<select id='"+id+"'></select>"+
"<div class='errors'></div>"+
"</div>"
);
customDropbox.attr("id", id);
$(this.element).replaceWith(customDropbox); // This removes original element from DOM
populateOptions(id);
},
});
}( jQuery ));
$(document).ready(function(){
$("#field1").dropbox(); //blank input field turns into a select with a label, populated options e.t.c..
$("#button1").on("click", function(){
$("#field1").dropbox("errorText", "This is a validation error message"); //throws an error saying dropbox is not initialized
});
});
</script>
<html>
<body>
<input id="field1" />
<button id="button1">Press me</button>
</body>
</html>
So I want a widget with public methods that will replace the original element with all the widget data associated with it. The problem with the above code is that the <select..> element is just a DOM element and if you call .dropbox(..) on it, it will say the widget is not initialized. Is there a way to make the select element into the widget object with the .errorText() method? All widget examples online add stuff around the original element but never replace it. As for the bigger picture, I'm trying to make a generic tool to configure forms dynamically. It's going to be all <input id="..."> in html but then javascript will query a database, get configuration for the field and turn it into a dropbox, checkbox or, say, a date picker with all the labels, validation, and other bells and whistles.

There is more than one issue with your widget code. I'll try to summarize them:
1. Copy the data
You're not copying the data to the newly created customDropbox, so before
this.element.replaceWith(customDropbox);
you should copy the data:
customDropbox.data(this.element.data());
Now the widget will remember that it was initialized.
2. this.element is gone
After
this.element.replaceWith(customDropbox);
you should update this.element so that it points to the newly created customDropbox:
this.element = customDropbox;
3. errorText message takes wrong element
Since the widgets element (this.element) is now pointing to the <div class='form-group'></div> element, the errorText function must be slightly modified to:
this.element.find(".errors").html(text);
4. id should be unique
Now, both the wrapper <div> and the <select> have the same id, which is not allowed in HTML so remove the one on the <select> tag. Luckily, <label> can work without the for attribute, just write it like this:
<label>labelForId <select></select></label>
Then to get the <select>-element, use this.element.find("select") in the widget.
Side note
`this.element` is already a jQuery element, so no need for the additional `$()` wrapping.
See this jsFiddle

function show(){
$("#field1").input({....});
}
function hide(){
$("#field1").input("hide");
}
<button onclick="show()">show</button>
<button onclick="hide()">hide</button>

i think to replace the origin element which initial dropbox() is not a good solution,
because this will force you to rely on the implemention details of jQuery ui factory,
it is easy to make a mistake or introduce bugs, sometimes harder for other people to understand your code
if jquery ui factory change the implemention in the future, you have to modify all your code to make it work
(sorry for my limit understand of jquery ui)
i think we can put the <input/> into a container and initial dropbox() on the container which inturn
replace <input/> with <select> datepicker ..etc.. we can build modules easily by doing so:
<form>
<div class="dropbox"><label for="someID">aaaaaa</label><input id="someID"/></div>
<div class="datepicker"></div>
<div class="othermodule"></div>
</form>
js:
$(".dropbox").dropbox(); // init dropbox you defined
$(".datepicker").datepicker(); // ...
$(".othermodule").othermodule(); // ...
$(".dropbox").dropbox("errorText", "error"); // invoke it smoothly
here is a simple demo: http://jsfiddle.net/m4A3D/
#Wouter Huysentruit's answer provides a list of good suggestion for me
<form>
<div class="dropbox">
<label for="someID">aaaaaa</label>
<input id="someID"/>
</div>
<div class="datepicker"></div>
<div class="othermodule"></div>
</form>
<button id="button1">Press me</button>
<script>
(function ($){
$.widget("my.dropbox", {
_create: function () {
var $input = this.element.find("input");
var sID = $input.attr("id");
var $select = $("<select>");
$select.attr("id", sID);
$input.replaceWith($select);
this.element.append("<div class='errors'></div>");
}, // end _create()
errorText: function (text) {
this.element.find(".errors").text(text);
} // end errorText()
});
}(jQuery));
$(".dropbox").dropbox();
$("#button1").click(function () {
$(".dropbox").dropbox("errorText", "this is error");
});
</script>

Related

JavaScript click event on div

I am working on JavaScript project and I am having a problem with click event and retrieving the correct information about the element clicked. I am relatively new to the JavaScript.
The real code I am working on is fairly complex however I am posting only a chunk of code to illustrate my problem.
function App(){
this.name = "New App";
}
App.prototype.createDIV = function() {
var h = "<div class='clickable' id='idToShow'><div class='name' id='notToShow'>" + this.name + "</div></div>";
$('#content').html(h);
}
App.prototype.showID = function(e) {
if (e.target.id == 'idToShow') {
alert(this.name); // this doesn't display, because incorrect ID is retrieved
}
}
$(document).ready(function() {
var newApp = new App();
$("input#btn").click(newApp.createDIV.bind(newApp));
$("div").on("click", ".clickable", newApp.showID.bind(newApp));
});
<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<div id="content"></div>
<input type="button" id="btn" value="CLICK">
I have a object in the app with number of prototypes. On document load, object is constructed, events are attached to elements and bind to object. Clicking the button, new set of div results are created dynamically.
Now this is where it starts to go wrong for me. I attached an event to div with the class CLICKABLE and I would like to retrieve the id of that particular DIV element (id='idToShow'); however I keep retrieving the id of the following DIV (id='notToShow').
I might not fully understand why is this happening and what to do to prevent it in order to get the correct ID.
Try using if (e.currentTarget.id == 'idToShow') instead of if (e.target.id == 'idToShow').

detect element where the function was called from

I need to know where my jQ function was called from...
In head:
function call_pl2(){
$(this).text('some text');
}
in Body:
<p> <script> call_pl2(); </script> </p>
<!-- OR -->
<div> <script> call_pl2(); </script> </div>
I got your point, I'm afraid you cannot get from the function the element that your js function is there, but each time that your function is called you can use another function and search your html content to see where this function is inside. I assume that this function is called ones from the html code when this is loaded.
Instead of trying to determine which element contains the the script tag (and, by extension, a particular call to call_pl2()) you could explicitly pass the containing element to call_pl2() as a parameter:
$(function() {
var call_p12 = function(element) {
if ($(element).is('p')) {
$(element).text('here is some text added to a paragraph');
}
if ($(element).is('div')) {
$(element).text('here is some text added to a div');
}
}
$('div, p').each(function() {
call_p12($(this));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<p></p>
<div></div>
It would be relatively easy to modify the call_p12() function to swap in a more specific selector in the jQuery is(). For example is('.someclass') to check for a class value instead of a tag name.

Append a div outside of the input parent

Im fairly new to javascript and I just can't figure this out despite my attempt in researching. How do I track the change of a input within a div and trigger an append to an outside div? My code goes as follow:
Append h3 with "Pending" once ".image-value" input has a change in value
<!-- APPEND <h3> -->
<h3>Best Overall Costume<div class="pending">Pending</div></h3>
<div>
<div class="select-form">
<img src="images/vote.jpg" data-value="image_value">
<img src="images/vote.jpg" data-value="image_value2">
<img src="images/vote.jpg" data-value="image_value3">
<img src="images/vote.jpg" data-value="image_value4">
<img src="images/vote.jpg" data-value="image_value5">
<!-- Track the change of this input -->
<input type="hidden" class="image-value" name="selected_image" value="">
</div>
</div>
I tried this:
function changeStatus(statusValue) {
$("input",".select-form").val(statusValue).trigger("change");
}
$("input",".select-form").change(function(){
if (!$(this).val()){
$("<div class='pending'>Pending</div>").appendTo($("h3").prev($(this)));
}
});
But that didn't seem to work. Any ideas?
place an empty div where you want your new div and give it an id i.e(<div id='myDiv'><div>) and then append what you want like this.
$( "#myDiv" ).append( "<div class='pending'>Pending</div>" );
You can also check Append Explained
for more explanations.
Thanks.
I've done a couple things here... First, I'm not sure why you had it all in a named function. When you're using event listeners that often isn't necessary.
Then, I don't know what the val check was for, so I reversed it.
Finally, I'm using one(), which only runs once. This case seemed to call for that.
$('.select-form').one('change', 'input', function () {
if ( $(this).val() ) { alert('asdgf');
$("<div class='pending'>Pending</div>")
.appendTo($(this).parent().prev('h3'));
}
});
Fiddle
try this:
$("input",".select-form").on("change", function(){
var $this = $(this);
if (!$this.val()){
var elem = $('<h3>Best Overall Costume<div class="pending">Pending</div></h3>');
$this.parent().parent().before(elem);
}
});
you can also place a check, that if the pending div is already added, not to add it again.
Of course this solution assumes that there are no other nested divs between the target div(before which you want to append) and the input control

Can't find the first direct child element of a div

Below is the code generating jQuery UI dialog from existing HTML template.
I want to extract title attribute from the HTML and use it as the title parameter for jQuery UI dialog method.
I tried children().first(), find(">:first-child"), etc but nothing worked.
titleStr is just undefined.
function define_Window() {
// constructor of class Window
MyNS.Window = function (path_html) {
this.DIV = $("<div/>").load(path_html);
var titleStr = this.DIV.children().first().attr("title");
// To test if DIVs are well appended
this.DIV2 = $("<div/>").attr("name", "Form").load(path_html);
$(MyNS.Windows).append(this.DIV2);
this.DLG = this.DIV.dialog({
title: titleStr
});
Template HTML files look like this:
<div title="THIS IS TITLEEEEEE!!!!">
<p>Description goes here</p>
<form>
<fieldset>
<label for="">blahblahblah
have you tried
var titleStr = "";
this.DIV = $("<div/>").load(path_html, function complete(responseText, textStatus, XMLHttpRequest) {
titleStr = $("div").first.attr("title");
} );
explanation: load gets the template through an asynchronous ajax request. therefore, the div alement carrying the title might not be available when you query for it in your code.
closure code adopts the call signature used by the jquery api spec for load.
I think in your case you don't need Child, try this:
First you are selecting this.DIV = $("div")
So, This will return array of elements. You can select the first by using this:
var first_div = this.DIV.eq(0)
// Now you can select its title:
first_div.attr('title');

how to get outerHTML with jquery in order to have it cross-browser

I found a response in a jquery forum and they made a function to do this but the result is not the same.
Here is an example that I created for an image button:
var buttonField = $('<input type="image" />');
buttonField.attr('id', 'butonFshi' + lastsel);
buttonField.val('Fshi');
buttonField.attr('src', 'images/square-icon.png');
if (disabled)
buttonField.attr("disabled", "disabled");
buttonField.val('Fshi');
if (onblur !== undefined)
buttonField.focusout(function () { onblur(); });
buttonField.mouseover(function () { ndryshoImazhin(1, lastsel.toString()); });
buttonField.mouseout(function () { ndryshoImazhin(0, lastsel.toString()); });
buttonField.click(function () { fshiClicked(lastsel.toString()); });
And I have this situation:
buttonField[0].outerHTML = `<INPUT id=butonFshi1 value=Fshi src="images/square-icon.png" type=image jQuery15205073038169030395="44">`
instead the outer function I found gives buttonField.outer() = <INPUT id=butonFshi1 value=Fshi src="images/square-icon.png" type=image>
The function is:
$.fn.outer = function(val){
if(val){
$(val).insertBefore(this);
$(this).remove();
}
else{ return $("<div>").append($(this).clone()).html(); }
}
so like this I loose the handlers that I inserted.
Is there anyway to get the outerHTML with jquery in order to have it cross-browser without loosing the handlers ?!
You don't need convert it to text first (which is what disconnects it from the handlers, only DOM nodes and other specific JavaScript objects can have events). Just insert the newly created/modified node directly, e.g.
$('#old-button').after(buttonField).remove();`
after returns the previous jQuery collection so the remove gets rid of the existing element, not the new one.
Try this one:
var html_text = `<INPUT id=butonFshi1 value=Fshi src="images/square-icon.png" type=image jQuery15205073038169030395="44">`
buttonField[0].html(html_text);
:)
Check out the jQuery plugin from https://github.com/darlesson/jquery-outerhtml. With this jQuery plugin you can get the outerHTML from the first matched element, replace a set of elements and manipulate the result in a callback function.
Consider the following HTML:
<span>My example</span>
Consider the following call:
var span = $("span").outerHTML();
The variable span is equal <span>My example</span>.
In the link above you can find more example in how to use .outerHTML() plug-in.
This should work fine:
var outer = buttonField.parent().html();

Categories

Resources