Basically I have two exact same divs and I want to add to both of them Bootstrap 4 color palette. Hard coding it is easy but I would like to do it in a dynamic way so theoretically future divs can have color palettes without writing new code manually.
The divs are (only the id is different):
<div id="myContainer">
<a class="color-picker">Pick color</a>
<input class="box" type="text" value="Write about yourself here">
</div>
<div id="myContainer2">
<a class="color-picker">Pick color</a>
<input class="box" type="text" value="Write about yourself here">
If I write this code, everything works fine:
var colorPickerArray = [];
$(function(){
colorPickerArray[0] = $('#myContainer .color-picker');
colorPickerArray[0].colorpicker();
colorPickerArray[0].on('changeColor', function(e){
$('#myContainer .color-picker').empty();
$('#myContainer .color-picker').append(' ');
if(e.color==null)
$(this).val('transparent').css('background-color', '#fff');//tranparent
else
$('#myContainer .box').css('color', e.color.toHex())
});
});
$(function(){
colorPickerArray[1] = $('#myContainer2 .color-picker');
colorPickerArray[1].colorpicker();
colorPickerArray[1].on('changeColor', function(e){
$('#myContainer2 .color-picker').empty();
$('#myContainer2 .color-picker').append(' ');
if(e.color==null)
$(this).val('transparent').css('background-color', '#fff');//tranparent
else
$('#myContainer2 .box').css('color', e.color.toHex())
});
});
It's just a duplication with different keys (0 and 1) and different divs ('#myContainer' and 'myContainer2'). But when I transform this code to a loop, it doesn't work:
var resizeArr = ['#myContainer', '#myContainer2'];
$(function(){
for (var i = 0; i < resizeArr.length; i++) {
colorPickerArray[i] = $(resizeArr[i] + ' .color-picker');
colorPickerArray[i].colorpicker();
colorPickerArray[i].on('changeColor', function(e){
$(resizeArr[i] + ' .color-picker').empty();
$(resizeArr[i] + ' .color-picker').append(' ');
if(e.color==null)
$(this).val('transparent').css('background-color', '#fff');//tranparent
else
$(resizeArr[i] + ' .box').css('color', e.color.toHex())
});
}
});
The actual code is exactly the same, just duplicated by the loop this time. Is it because changing the value of i affects the event listeners? What should I do instead of using arrays here?
Edit
I did come out with a solution to create those dynamic color palettes and I would like to share it for whom it may help. But please I would still love to know why the previous method doesn't work, just for deeper understanding of js.
Anyway, here is the solution:
$('body > div .color-picker').mousedown(function(e) {
var target = $(e.target);
for (var i = 0; i < resizeArr.length; i++) {
if (target.is($(resizeArr[i] + ' .color-picker i'))) {
var a = $(resizeArr[i] + ' .color-picker');
a.colorpicker();
a.on('changeColor', function(e){
var b = (a[0].parentElement);
b = '#' + b.id
$(b + ' .color-picker').empty();
$(b + ' .color-picker').append(' ');
if(e.color==null)
$(this).val('transparent').css('background-color', '#fff');//tranparent
else
$(b + ' .color-picker').val(e.color).css('background-color', e.color);
$(b + ' .box').css('color', e.color.toHex())
});
}
}
});
one problem i see is you're using resizeArr[i] in event 'changeColor', i is resizeArr.length when it executes due to scoping.
you can read more about let here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
You can use follow method, by create current name variable for each colorPickerArray[i]:
var colorPickerArray = [];
var resizeArr = ['#myContainer', '#myContainer2'];
$(function(){
for (var i = 0; i < resizeArr.length; i++) {
colorPickerArray[i] = $(resizeArr[i] + ' .color-picker');
colorPickerArray[i].colorpicker();
colorPickerArray[i].on('changeColor', function(e){
//console.log(resizeArr[i]); //undefined here!
var current = $(this).parent();
var name = "#" + current[0].id; //console.log(current[0].id);
$(name + ' .color-picker').empty();
$(name + ' .color-picker').append(' ');
if(e.color==null)
$(this).val('transparent').css('background-color', '#fff');//tranparent
else
$(name + ' .color-picker').val(e.color).css('background-color', e.color);
$(name + ' .box').css('color', e.color.toHex())
});
}
});
Related
Following previous post the this code works and does the job but I am conscious this is about as DRY as the Pacific on a wet day.
I's be grateful for any suggestions that will make it more efficient.
$( "#cvl_mb_services .content-switch" ).each(function(index, el) {
var parent = $(el).parent().parent().attr("id");
var inputValue = $('#' + parent + ' input[type=radio]:checked').val();
var targetBox = '#' + parent + ' .cvl-' + inputValue + '-fields';
$(targetBox).removeClass('cvl-hide');
});
$('#cvl_mb_services .content-switch').on('click', 'input[type="radio"]', function(){
var parent = $(this).parent().parent().parent().parent().parent().parent().attr("id");
var inputValue = $(this).closest('input[type="radio"]').attr("value");
var targetBox = '#' + parent + ' .cvl-' + inputValue + '-fields';
if (inputValue == 'content') {
$('#' + parent + ' .cvl-content-fields').removeClass('cvl-hide');
$('#' + parent + ' .cvl-header-fields').addClass('cvl-hide');
$('#' + parent + ' .cvl-footer-fields').addClass('cvl-hide');
} else if (inputValue == 'header') {
$('#' + parent + ' .cvl-content-fields').addClass('cvl-hide');
$('#' + parent + ' .cvl-header-fields').removeClass('cvl-hide');
$('#' + parent + ' .cvl-footer-fields').addClass('cvl-hide');
} else if (inputValue == 'footer') {
$('#' + parent + ' .cvl-content-fields').addClass('cvl-hide');
$('#' + parent + ' .cvl-header-fields').addClass('cvl-hide');
$('#' + parent + ' .cvl-footer-fields').removeClass('cvl-hide');
}
});
Several points to make it more DRY:
Use only one var keyword, and separate the items with commas. Ex. var asdf = 1, sdfg = '', dfgh = true;
Use multiple selectors so you apply the .addClass action only once. See https://api.jquery.com/multiple-selector/
Find a way to get rid of this duplication, such as perhaps adding/using a class to select the right ancestor: .parent().parent().parent().parent().parent().parent()
Don't duplicate strings like 'cvl-hide' Instead make a variable. Many JavaScript minifiers won't touch strings, so you'll end up with this duplication making your overall file larger than it needs to be.
Make variables for duplicate selectors so jQuery doesn't have to do the same lookup twice. For stuff like $('#cvl_mb_services .content-switch') and even for stuff like $(this) which is duplicated.
This is my code so far
var items = [];
function addItems () {
items.push(document.getElementById("txtArea").value);
document.getElementById('txtArea').value = '';
console.log('items = [' + items + ']');
}
function displayItems () {
var tag1 = '<p>',
tag2 = '</p>';
for(var i in items) {
document.write(tag1 + 'Element ' + i + ' = ' + items[i] + tag2);
}
}
<input type='text' id='txtArea'>
<input type="button" value="Add" id="addButton" onclick='addItems()'>
<input type="button" value="Display" id="displayButton" onclick='displayItems()'><hr>
<p id='elements'></p>
In the text field I add numbers that are pushed to an array. When I press display it should display all the elements of that array after the horizontal line, but instead it opens a new page with all of those elements.
What I want is to display elements after the horizontal line in the same page. Could someone please help me?
You need to set the text of paragraph elements
document.getElementById('elements').innerHTML = 'New Value';
instead of
document.write(....)
var items = [];
function addItems() {
items.push(document.getElementById("txtArea").value);
document.getElementById('txtArea').value = '';
console.log('items = [' + items + ']');
}
function displayItems() {
var tag1 = '<p>',
tag2 = '</p>',
str = '';
for (var i in items) {
str += tag1 + 'Element ' + i + ' = ' + items[i] + tag2 + '<br/>';
}
document.getElementById('elements').innerHTML = str;
}
<input type='text' id='txtArea'>
<input type="button" value="Add" id="addButton" onclick='addItems()'>
<input type="button" value="Display" id="displayButton" onclick='displayItems()'>
<hr>
<p id='elements'></p>
document.write() will erase all data in body so you cannot use it after load.
Try to make a text var,
var text = "";
then append in loop
text += tag1 + 'Element ' + i + ' = ' + items[i] + tag2
At the end do
document.body.innerHTML = text;
If i understand your problem correctly, I believe you can do something like this, unfortunately i do not have time to try it myself.
var bodytag = document.getElementsByTagName('body');
for(var i in items) {
var e = document.createElement('p');
e.innerHTML = 'Element ' + i + ' = ' + items[i]
bodytag.appendChild(e);
}
Good luck.
I managed to get it working using this example from w3schools: w3schools.com/jsref/tryit.asp?filename=tryjsref_doc_body_append .
I've deleted the <p id='elements'></p> tag from the html code and modified the displayItems function like this:
function displayItems () {
for(var i in items) {
var e = document.createElement("p");
var t = document.createTextNode('Element ' + i + ' = ' + items[i]);
e.appendChild(t);
document.body.appendChild(e);
}
Thank you all for your help.
Use
document.getElementsByTagName("BODY")[0].html = sth;
instead of:
document.write..
I am building a Twitter like site that is fed random tweets that I want to export to the website in a particular manner. I have most of my requirements met up to this point, the only issue I am having is turning the jQuery text of a Twitter user and handle it into a link that can be clicked.
My code snippet below exhibits my work so far:
<script>
$(document).ready(function(){
var $body = $('.middle');
$body.html();
var index = streams.home.length - 1;
var newTweets = function(index){
while(index >= 0){
var tweet = streams.home[index];
var $tweet = $('<div class=tweetBox></div>');
$tweet.text('#' + tweet.user + ': ' + tweet.message + tweet.created_at);
$tweet.appendTo($body);
index -= 1;
}
}
newTweets(index);
$('button').on('click', function(){
index = streams.home.length - 1;
newTweets(index);
});
});
</script>
The line that is giving the issue is $tweet.text('#' + tweet.user + ': ' + tweet.message + tweet.created_at);
I want to take tweet.user and convert it into a click-able link. Any suggestions on ways to attack this would be very much appreciated.
You have to use the HTML function of jQuery. http://api.jquery.com/html/
like this:
var link = $('<a>', {text: tweet.user, href: '#'}).prop('outerHTML');
$tweet.html('#' + link + ': ' + tweet.message + tweet.created_at);
it will do the work.
If I understand correctly, then this is what you want
var link = $('<a>', {text: tweet.user, href: '#'}).prop('outerHTML');
$tweet.html('#' + link + ': ' + tweet.message + tweet.created_at);
I'm currently working on an idea whiteboard, but it seems that whenever I try to delete comments, blank spaces are left between the ideas.
For example, if I have the following comments:
But when I delete something:
How would I make it so that no gaps are left between comments?
Here is my code so far:
jQuery(function ($) {
$('#chat').on('click', '.delete', function(e) {
$(this).parent().remove();
});
var socket = io.connect();
var $messageForm = $('#sendmessage');
var $messageTitle = $('#title');
var $messageBox = $('#message');
var $chat = $('#chat');
$messageForm.click(function (e) {
if ($.trim($("#title").val()).length === 0) {
alert('You must provide valid input');
$messageTitle.val('');
$messageBox.val('');
return false;
}
if ($.trim($("#message").val()).length === 0) {
alert('You must provide valid input');
$messageTitle.val('');
$messageBox.val('');
return false;
} else {
e.preventDefault();
socket.emit('send message', '<span class="idea"><b>' + $messageTitle.val() + '</b>' + ' - ' + $messageBox.val() + ' ' + '[' + '<a class="delete" href="#">Delete</a>' + ']</span>');
$messageTitle.val('');
$messageBox.val('');
}
});
socket.on('new message', function (data) {
$chat.prepend(data + "<br/>");
});
});
The HTML that remains:
<div id="chat"><span class="idea"><b>sfdf</b> - czxczxc [<a class="delete" href="#">Delete</a>]</span>
<br><span class="idea"><b>dsdfsd</b> - sdfsdfsdf [<a class="delete" href="#">Delete</a>]</span>
<br>
<br><span class="idea"><b>dsfsdf</b> - sdfsdf [<a class="delete" href="#">Delete</a>]</span>
<br>
</div>
Instead of using <br>s to separate ideas, just add a CSS rule so that each idea is on its own line
<style>span.idea { display: block }</style>
and then
$chat.prepend(data + "<br/>");
becomes
$chat.prepend(data);
hopefully after you've filtered data to prevent XSS.
I believe you should use 'remove' instead of 'empty'.
Empty does not remove the element, it just empties it.
Manual:
http://api.jquery.com/remove/
i guess its the br that is still in the dom, that you insert by doing this:
$chat.prepend(data + "<br/>");
maybe you change you code so that it uses a list, that would look like this:
<ul>
<li class="id">message1</li>
<li class="id">message2</li>
</ul>
you would have to edit change these lines:
socket.emit('send message', '<li class="idea"><b>' + $messageTitle.val() + '</b>' + ' - ' + $messageBox.val() + ' ' + '[' + '<a class="delete" href="#">Delete</a>' + ']</li>');
some lines below change this:
$chat.prepend(data);
and on top add this:
var chatUlElement = $('ul');
var $chat = $('#chat').append(chatUlElement);
I have created nestled arrays, which I then append to a div. When i click the button with id "name", a movie with title is stored in an array $titelBetyg, which is later stored in another array $films. Whenever i create a new $titelBetyg, i want to remove the previous $films from my div, before replacing it with the new one. How do I do this?
Javascript
$(document).ready(function(){
var $films = [];
$('#name').keyup(function(){
$('#name').css('background-color', 'white');
});
$('#options').change(function(){
$('#options').css('background-color', 'white');
});
$("#button").click(function(){
var $titelBetyg = [];
var $titel = $('#name').val();
var $betyg = $('#options').val();
if($titel == ""){
$('#name').css('background-color', 'red');
alert("Fail");
}
else if($betyg == "0"){
$('#options').css('background-color', 'red');
alert("Fail");
}
else{
$titelBetyg.push($titel);
$titelBetyg.push($betyg);
$films.push($titelBetyg);
// here is where i need to remove it before appending the new one
$('#rightbar').append("<ul>");
for(i=0; i<$films.length; i++){
$('#rightbar').append("<li>" + $films[i][0] + " " + $films[i][1] + "</li>" + "<br>");
}
$('#rightbar').append("</ul>");
}
});
$('#stigande').click(function(a,b){
});
$('#fallande').click(function(){
});
});
Use .empty() like this (and append to the <ul> instead of something else):
var $ul = $("<ul>");
for (var i=0; i<$films.length; i++) {
$ul.append("<li>" + $films[i][0] + " " + $films[i][1] + "</li><br>");
}
$('#rightbar').empty().append($ul);
Btw, it might be easier to only append the new one instead of emptying and rebuilding the whole thing:
$('#rightbar ul').append("<li>" + $titel + " " + $betyg + "</li><br>");
To remove only the list contents (and nothing else) from the #rightbar, you could use this:
var $ul = $('#rightbar ul').empty();
if (!$ul.length) // if nonexistent…
$ul = $("<ul>").appendTo('#rightbar'); // create new one
for (var i=0; i<$films.length; i++)
$ul.append("<li>" + $films[i][0] + " " + $films[i][1] + "</li>");
document.getElementById('rightbar').innerHTML = '';
That way rightbar is totally empty.
You only require to remove the content of the container. So, use the .empty() function
$('#rightbar').empty().append("<ul>"); //It will empty the content and then append
for(i=0; i<$films.length; i++){
$('#rightbar').append("<li>" + $films[i][0] + " " + $films[i][1] + "</li>" + "<br>");
}
$('#rightbar').append("</ul>");