JQuery selectable functions [closed] - javascript

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
can anyone help me with my js selector functions? The problem is the color and size indicator numbers showing do not default back to "blank" after mouseout. I want the indicator number to disappear after mouseout if a mouseclick never happens over the function. Can anyone help? My demo http://jsfiddle.net/jwjxr2oh/3/
Thanks

The problem is when sizeIndicator.data('selected') is not present sizeIndicator.data('selected') will return undefined, then the text() method will act like a getter method and will not update the value to blank so
$(function() {
var colorsList = $('#colors');
var sizesList = $('#sizes');
var colorIndicator = $('#color_indicator');
var sizeIndicator = $('#size_indicator');
var colors = [{
id: 1,
name: 'Dark Blue Denim',
color: '#0B3861'
}, {
id: 2,
name: 'Light Blue Denim',
color: '#81BEF7'
}];
var sizes = [{
id: 1,
name: '26'
}, {
id: 2,
name: '28'
}, {
id: 2,
name: '30'
}, {
id: 3,
name: '32'
}];
$.each(colors, function() {
colorsList.append(
$('<li>').attr({
id: 'color_' + this.id
})
.data('info', this)
.append(
$('<div>').css('background-color', this.color)));
});
$.each(sizes, function() {
sizesList.append(
$('<li>').attr({
id: 'size_' + this.id
})
.data('info', this)
.text(this.name)
.addClass('text'));
});
colorsList.selectable({
selected: function(event, ui) {
var total = $(ui.selected).siblings('li.ui-selected').length + 1;
if (total > 1) {
$(ui.selected).removeClass('ui-selected');
} else {
var color = $(ui.selected).data('info').name;
colorIndicator.data('selected', color).text(color);
}
}
});
sizesList.selectable({
selected: function(event, ui) {
var total = $(ui.selected).siblings('li.ui-selected').length + 1;
if (total > 1) {
$(ui.selected).removeClass('ui-selected');
} else {
var size = $(ui.selected).data('info').name;
sizeIndicator.data('selected', size).text(size);
}
}
});
sizesList.children('li').hover(function() {
sizeIndicator.text($(this).data('info').name);
}, function() {
console.log(sizeIndicator)
sizeIndicator.text(sizeIndicator.data('selected') || '');
});
colorsList.children('li').hover(function() {
colorIndicator.text($(this).data('info').name);
}, function() {
colorIndicator.text(colorIndicator.data('selected') || '');
});
$('#show').click(function() {
var color = colorsList.find('li.ui-selected').eq(0).data('info');
var size = sizesList.find('li.ui-selected').eq(0).data('info');
if (typeof color != 'undefined') {
alert('Color selected: ' + color.name + ', id: ' + color.id);
}
if (typeof size != 'undefined') {
alert('Size selected: ' + size.name + ', id: ' + size.id);
}
});
});
.selectable li.ui-selecting {} .selectable li.ui-selected {
border: 1px solid #000;
}
.selectable {
list-style-type: none;
margin: 0;
padding: 0;
}
.selectable li {
border: 1px solid #fff;
margin: 3px;
padding: 3px;
float: left;
text-align: center;
}
.selectable li:hover {
border: 1px solid #000;
margin: 3px;
padding: 3px;
cursor: pointer;
cursor: hand;
float: left;
text-align: center;
}
.selectable li div {
border: 1px solid #000;
padding: 5px;
margin: 3px;
width: 20px;
height: 20px;
}
.selectable li.text {
color: #000;
padding: .5em .5em;
margin: .5em 1em;
font-size: 1.5em;
border-radius: 50%;
-webkit-transition: all 0.2s ease-in-out;
-moz-transition: all 0.2s ease-in-out;
-o-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
line-height: 1em;
}
.selectable li.text:hover {
cursor: pointer;
cursor: hand;
color: #000;
font-weight: normal;
border: 1px solid #000;
}
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js"></script>
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/redmond/jquery-ui.css">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.js"></script>
<input type='button' id='show' value='What is selected?'>
<table width="595" height="172" border="0">
<tr>
<td width="421" height="40" align="center" valign="middle">Size: <span id="size_indicator"></span>
</td>
<td width="164">Color: <span id="color_indicator"></span></td>
</tr>
<tr>
<td height="103">
<ol id="sizes" class='selectable'></ol>
</td>
<td>
<ol id="colors" class='selectable'></ol>
</td>
</tr>
</table>

Related

Hiding an element in internet explorer leaves artifacts on the screen (IE 10-11)

We use custom selectbox elements for our page (for reasons), but in one specific place and only with IE (in my case version 10 and 11), there is a problem.
When you open the box and close it, sometimes the browser leaves visual artifacts of that element. If there is a button below the element (in the opened state), then those artifacts are still on top of that button UNTIL you hover over the button, then those artifacts disappear at that place.
I think everyone experienced this behaviour at some point in his life with windows or something else. Sorry if my description isn't perfect.
Here are some screenshots (The red boxes are censored text, sorry):
Open state:
Closed state with artifacts:
Hope my description is accurate, I desperately need a fix for this.
I can't reproduce it on my system, but our QA guy can reproduce it consistently. It also changes depending on the size of the browser. On some sizes it doesn't seem to happen at all. It must be some weird rendering glitch of IE.
I don't think it has anything to do with our custom selectbox element, because it happens only in this specific place and in our old design we experienced it in a different place with a completely different element. At that time I thought it's because the DOM is too complicated for IE, but this page has almost no elements.
EDIT: I Just found out that if I minimize the window and maximize it again, the artifacts disappear, which should confirm that this is a rendering glitch, right?
EDIT 2: Here is the code and css of our custom selectbox
HTML:
<div class="input_selectbox">
<label>Title</label>
<div class="input_selectbox__head" data-placeholder="">
<label>
<input type="hidden" name="id" value="5-10909">
Dummy 1
</label>
</div>
<div class="input_selectbox__body">
<label data-value="" class="">
No Option
</label>
<label id="5-10909" data-value="5-10909" class="input_selectbox__option--selected" data-default="true">
Dummy 1
</label>
<label id="5-12568" data-value="5-12568" class="">
Dummy 2
</label>
<label id="5-20001" data-value="5-20001" class="">
Dummy 3
</label>
<label id="5-20002" data-value="5-20002" class="">
Dummy 4
</label>
</div>
</div>
LESS:
.input_combobox, .input_selectbox {
display: block;
font-family: RobotoCondensed-Regular;
font-size: 14px;
width: 100%;
overflow: hidden;
&:focus {
outline: none;
}
label {
cursor: pointer;
}
}
.input_selectbox {
font-family: Roboto-Regular;
}
.input_selectbox__head {
border: 1px solid #colorBorderGrey;
transition: background-color 0.2s, border 0.3s;
overflow-x: hidden;
text-overflow: ellipsis;
display: flex;
background-color: #colorLightestGrey;
padding: 10px;
justify-content: space-between;
&:hover {
cursor: pointer;
border-color: #colorDarkGrey;
&:after {
color: #colorBlue;
}
}
label {
display: flex;
user-select: none;
pointer-events: none;
i {
margin-right: 10px;
}
}
&:after {
content: "\f078";
font-style: normal;
font-variant: normal;
text-rendering: auto;
font-family: "Font Awesome 5 Pro";
font-weight: 900;
pointer-events: none;
transition: color 0.3s, opacity 0.3s, background-color 0.2s;
display: block;
padding-left: 10px;
font-size: 16px;
}
}
.input_combobox--active, .input_selectbox--active {
.input_combobox__head, .input_selectbox__head {
background-color: #colorLightGrey;
&:hover {
border: 1px solid #colorBorderGrey;
&:after {
color: #colorDarkGrey;
}
}
&:after {
background-color: #colorLightGrey;
}
span {
background-color: #colorGreyHover;
}
}
}
.input_combobox__body, .input_selectbox__body {
display: none;
position: fixed;
box-shadow: rgba(0,0,0, 0.05) 0px 2px 5px 0px;
background-color: #colorWhite;
border: 1px solid #colorBorderGrey;
border-top: none;
max-height: 400px;
overflow-y: auto;
width: 100%;
z-index: 499;
label {
font-family: RobotoCondensed-Regular;
font-size: 16px;
display: block;
padding: 10px 20px;
transition: background-color 0.5s, color 0.3s;
border-bottom: 1px solid #colorBorderGrey;
&:hover {
background-color: #colorLightGrey;
}
&:last-child {
border-bottom: none;
}
i {
margin-right: 10px;
}
input[type=checkbox] {
display: none;
}
}
}
.input_combobox__body--top, .input_selectbox__body--top {
box-shadow: rgba(0, 0, 0, 0.1) 0px -2px 5px 0px;
}
.input_combobox__option--inactive, .input_selectbox__option--inactive {
opacity: 0.3;
}
Javascript:
function selectbox()
{
// click
$(document).on("click", ".input_selectbox__head", function ()
{
$(this).trigger("selectbox:toggle");
});
// toggle
$(document).on("selectbox:toggle", ".input_selectbox__head", function ()
{
if ($(this).parent().hasClass("input_selectbox--active"))
{
$(this).trigger("selectbox:close");
}
else
{
$(this).trigger("selectbox:open");
}
});
// open
$(document).on("selectbox:open", ".input_selectbox__head", function ()
{
var selectbox = $(this).closest(".input_selectbox");
if (!selectbox.hasClass("readonly") && !selectbox.hasClass("input--disabled"))
{
$(".input_selectbox--active .input_selectbox__head").trigger("selectbox:close");
// Positionierung
var header = selectbox.find(".input_selectbox__head");
var headerHeight = header.outerHeight();
var selectboxBody = selectbox.find(".input_selectbox__body");
var headerPositionX = header.offset().left;
var headerPositionY = header.offset().top - $(window).scrollTop();
var bodyPositionY = headerPositionY + headerHeight;
selectboxBody.removeClass("input_selectbox__body--top");
selectboxBody.css({
"top": bodyPositionY,
"left": headerPositionX,
"width": selectbox.width(),
"bottom": ""
});
selectbox.addClass("input_selectbox--active");
selectboxBody.show();
// check if offscreen
var isOut = isOutOfViewport(selectboxBody.get(0));
if (isOut.bottom)
{
selectboxBody.addClass("input_selectbox__body--top");
selectboxBody.css({
top: "",
bottom: ($(window).innerHeight() - headerPositionY - 1)
});
}
// close combobox on parent scroll
var scrollParent = getScrollParent(header[0]);
$(scrollParent).one("scroll", function ()
{
header.trigger("selectbox:close");
});
$(document).one("scroll", function ()
{
header.trigger("selectbox:close");
});
$(window).one("resize", function ()
{
header.trigger("selectbox:close");
});
}
});
// close
$(document).on("selectbox:close", ".input_selectbox__head", function ()
{
var selectbox = $(this).closest(".input_selectbox");
selectbox.removeClass("input_selectbox--active");
var selectboxBody = selectbox.find(".input_selectbox__body");
selectboxBody.hide();
});
// change option
$(document).on("click", ".input_selectbox__body > label", function ()
{
var label = $(this);
var value = label.attr("data-value");
var headerLabel = $(this).closest(".input_selectbox__body").siblings(".input_selectbox__head").children("label");
var name = headerLabel.find("input[type=hidden]").attr("name");
label.addClass("input_selectbox__option--selected").siblings().removeClass("input_selectbox__option--selected");
headerLabel.html(label.html());
headerLabel.append('<input type="hidden" name="' + name + '" value="' + value + '" />');
headerLabel.closest(".input_selectbox__head").trigger("selectbox:close");
$(this).closest(".input_selectbox").trigger("selectbox:change").trigger("change");
});
// close selectbox on outside click
$(document).ready(function ()
{
$(document).on("click touchstart", function (event)
{
if ($(event.target).closest('.input_selectbox--active').length == 0)
{
$(".input_selectbox--active .input_selectbox__head").trigger("selectbox:close");
}
});
});
// form reset
$(document).on("reset", "form", function ()
{
var selectboxes = $(this).find(".input_selectbox");
selectboxes.each(function ()
{
$(this).find(".input_selectbox__body").find("label[data-default=true]").click();
});
});
}

show dynamic array with vue

im newbie with vue so i have a couple of cuestions, im showing a table with some data that i get from a web-service, the thing is , that i dont always get the same amount of data, the data comes in an array, for example like this
var todos = [
{name : "dexter" , color : "orange"},
{name : "jaime", color : "green" },
{name : "stack", color : "yellow" },
{name : "overflow", color : "black" }
]
but as i say, I dont alway's get a response with 2 items in it,
right now i have to declare what item in te array im calling to, and i want to call all the items in the array to show them
var todos = [
{
name: "dexter",
color: "orange"
},
{
name: "jaime",
color: "green"
},
{
name: "stack",
color: "yellow"
},
{
name: "overflow",
color: "black"
}
]
var i = 0;
var sixthTable = new Vue({
el: '#sevenTable',
data: {
currentPage: 1,
elementsPerPage: 3,
ascending: false,
sortColumn: '',
rows: [
{
name: todos[0].name,
color: todos[0].color
},
{
name: todos[1].name,
color: todos[1].color
},
{
name: todos[2].name,
color: todos[2].color
},
{
name: todos[3].name,
color: todos[3].color
}
]
},
methods: {
"sortTable": function sortTable(col) {
if (this.sortColumn === col) {
this.ascending = !this.ascending;
} else {
this.ascending = true;
this.sortColumn = col;
}
var ascending = this.ascending;
this.rows.sort(function(a, b) {
if (a[col] > b[col]) {
return ascending ? 1 : -1
} else if (a[col] < b[col]) {
return ascending ? -1 : 1
}
return 0;
})
},
"num_pages": function num_pages() {
return Math.ceil(this.rows.length / this.elementsPerPage);
},
"get_rows": function get_rows() {
var start = (this.currentPage - 1) * this.elementsPerPage;
var end = start + this.elementsPerPage;
return this.rows.slice(start, end);
},
"change_page": function change_page(page) {
this.currentPage = page;
}
},
computed: {
"columns": function columns() {
if (this.rows.length == 0) {
return [];
}
return Object.keys(this.rows[0])
}
}
});
table {
font-family: 'Open Sans', sans-serif;
width: 750px;
border-collapse: collapse;
border: 3px solid #44475C;
margin: 10px 10px 0 10px;
}
table th {
text-transform: uppercase;
text-align: left;
background: #44475C;
color: #FFF;
cursor: pointer;
padding: 8px;
min-width: 30px;
}
table th:hover {
background: #717699;
}
table td {
text-align: left;
padding: 8px;
border-right: 2px solid #7D82A8;
}
table td:last-child {
border-right: none;
}
table tbody tr:nth-child(2n) td {
background: #00B4BB;
}
table {
font-family: 'Open Sans', sans-serif;
width: 750px;
border-collapse: collapse;
border: 3px solid #44475C;
margin: 10px 10px 0 10px;
}
table th {
text-transform: uppercase;
text-align: left;
background: #44475C;
color: #FFF;
cursor: pointer;
padding: 8px;
min-width: 30px;
}
table th:hover {
background: #007b80;
}
table td {
text-align: left;
padding: 8px;
border-right: 2px solid #7D82A8;
}
table td:last-child {
border-right: none;
}
table tbody tr:nth-child(2n) td {
background: #D4D8F9;
}
.pagination {
font-family: 'Open Sans', sans-serif;
text-align: right;
width: 750px;
padding: 8px;
}
.arrow_down {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB8AAAAaCAYAAABPY4eKAAAAAXNSR0IArs4c6QAAAvlJREFUSA29Vk1PGlEUHQaiiewslpUJiyYs2yb9AyRuJGm7c0VJoFXSX9A0sSZN04ULF12YEBQDhMCuSZOm1FhTiLY2Rky0QPlQBLRUsICoIN/0PCsGyox26NC3eTNn3r3n3TvnvvsE1PkwGo3yUqkkEQqFgw2Mz7lWqwng7ztN06mxsTEv8U0Aam5u7r5EInkplUol/f391wAJCc7nEAgE9Uwmkzo4OPiJMa1Wq6cFs7Ozt0H6RqlUDmJXfPIx+qrX69Ti4mIyHA5r6Wq1egND+j+IyW6QAUoul18XiUTDNHaSyGazKcZtdgk8wqhUKh9o/OMvsVgsfHJy0iWqVrcQNRUMBnd6enqc9MjISAmRP3e73T9al3XnbWNjIw2+KY1Gc3imsNHR0YV4PP5+d3e32h3K316TySQFoX2WyWR2glzIO5fLTSD6IElLNwbqnFpbWyO/96lCoai0cZjN5kfYQAYi5H34fL6cxWIZbya9iJyAhULBHAqFVlMpfsV/fHxMeb3er+Vy+VUzeduzwWC45XA4dlD/vEXvdDrj8DvURsYEWK3WF4FA4JQP9mg0WrHZbEYmnpa0NxYgPVObm5teiLABdTQT8a6vrwdRWhOcHMzMzCiXlpb2/yV6qDttMpkeshEzRk4Wo/bfoe4X9vb2amzGl+HoXNT29vZqsVi0sK1jJScG+Xx+HGkL4Tew2TPi5zUdQQt9otPpuBk3e0TaHmMDh1zS7/f780S0zX6Yni+NnBj09fUZUfvudDrNZN+GkQbl8Xi8RLRtHzsB9Hr9nfn5+SjSeWUCXC7XPq5kw53wsNogjZNohYXL2EljstvtrAL70/mVaW8Y4OidRO1/gwgbUMvcqGmcDc9aPvD1gnTeQ+0nmaInokRj0nHh+uvIiVOtVvt2a2vLv7Ky0tL3cRTXIcpPAwMDpq6R4/JXE4vFQ5FI5CN+QTaRSFCYc8vLy1l0rge4ARe5kJ/d27kYkLXoy2Jo4C7K8CZOsEBvb+9rlUp1xNXPL7v3IDwxvPD6AAAAAElFTkSuQmCC')
}
.arrow_up {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAaCAYAAACgoey0AAAAAXNSR0IArs4c6QAAAwpJREFUSA21Vt1PUmEYP4dvkQ8JFMwtBRocWAkDbiqXrUWXzU1rrTt0bdVqXbb1tbW16C9IBUSmm27cODdneoXjputa6069qwuW6IIBIdLvdaF4OAcOiGeDc87zPs/vd57P96WpFq7p6enbGo1mjKZpeTabjU1MTCRagGnOZHFxcXxtbe1XKpUq7+zslJeXl//Mz8+Hy+Uy3RxSE9qTk5M3otFooVQqgef4Wl9f343FYoEmoISrxuNxFX5f9vb2jhn/PxUKhfLS0tIPfFifUESRUMV8Pv/M6XReRm5rTGQyGeXxeGxYe1ezeBpBOBx2rKysbO7v79d4Wy3Y2Nj4GQqFbgnhaugxwiuGJx99Pp9FLBbXxYTXvTqd7v3MzIy6riIWGxJnMpl7AwMD14xGYyMsSq1WUyQdUqn0eSPlusQIsbGrq+vl4OCgvhFQZd1utyv1en0gEolcqsi47nWJlUrlG5fLZVcoFFy2nDKSDpIWlUoVTCQSEk4lCHmJMZ2GTCbTiMVikfIZ88l7enoos9l8dXt7+z6fDicxSJUokqDX6xXcl2wCROoc0vQCWL3sNfLOSdzR0fHY4XC4tVotl40gmVwup9xuN4OQv+UyqCFGH9rg7SOGYVRcBs3IEG4J0nVnamrqOtvuBDGGgQg9+wHFcVEi4a0LNkbdd6TrPKo8ODc311mteIIYjT/a398/jK+s1jnVM0kXoufCFvq0GuiIGEVgQIhfoygM1QrteEa9dAL7ITiYCt4RMabOK5AyKKzKWtvupLcRciu8D5J0EuDDPyT/Snd39yh6VtY2NhYQSR9G79Ds7OxdskRjEyAufvb7/cPoO5Z6e1+xtVKrq6vfcFzyi/A3ZrPZ3GdNSlwgo5ekE4X2RIQGf2C1WlufFE0GBeGWYQ8YERWLxQtnUVB830MKLZfL9RHir8lkssCn2G751tZWEWe03zTKm15YWPiEiXXTYDB0Ig/t7yd8PRws4EicwWHxO4jHD8/C5HiTTqd1BwcHFozKU89origB+y/kmzgYpgOBQP4fGmUiZmJ+WNgAAAAASUVORK5CYII=')
}
.arrow {
float: right;
width: 12px;
height: 15px;
background-repeat: no-repeat;
background-size: contain;
background-position-y: bottom;
}
.number {
display: inline-block;
padding: 4px 10px;
color: #000000;
border-radius: 4px;
background: #00B4BB;
margin: 0px 5px;
cursor: pointer;
}
.number:hover,
.number.active {
background: #ccfdff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.js"></script>
<div id="sevenTable">
<table>
<thead>
<tr>
<th v-for="col in columns" v-on:click="sortTable(col)">{{col}}
<div class="arrow" v-if="col == sortColumn" v-bind:class="[ascending ? 'arrow_up' : 'arrow_down']"></div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in get_rows()">
<td v-for="col in columns">{{row[col]}}</td>
</tr>
</tbody>
</table>
<div class="pagination">
<div class="number" v-for="i in num_pages()" v-bind:class="[i == currentPage ? 'active' : '']" v-on:click="change_page(i)">{{i}}</div>
</div>
here is my full code i know my array its not actually a web-servce response i put in that way to "simplify" de code
thanks in advice
You can just assign the web-service-provided data right into your data like
rows: todos

How to pass a parentNode.id as a parameter to an element out of the querySelector

I have these elements created inside a "querySelector('ul'). It's working property.
I want the "blue-Save" button to have the same function as the "yellow-Save".
But the Blue-save button was created in the HTML file, and the Yellow-Save button was created in JavaScript to listen to an event from the "querySelector('ul').
Is there anyway I can just link the Blue-Save to react as if I was clicking in the Yellow-Save?
(I'm sorry if I didn't explain it property or If it seems too confused, this is my first application, It doesn't seems too organized but I'm focused in making things work before dive in 'well developed apps').
Thank You Everyone!
var todoList = {
todos: [],
addTodo: function (todoText) {
this.todos.push({
todoText: todoText,
/*the name of the property (even if it is the same name as the parameter) never change. Only the value, which follows in this case is following the parameter*/
completed: false
});
},
changeTodo: function (position, todoText) {
this.todos[position].todoText = todoText;
},
deleteTodo: function (position) {
this.todos.splice(position, 1);
},
toggleCompleted: function (position) {
var todo = this.todos[position];
todo.completed = !todo.completed;
/*Here we flip the boolean to his oposite value. if todo.completed is equal false, so changes it to true, and so on. */
},
toggleAll: function () {
// recording the number of todos and completed todos
var totalTodos = this.todos.length;
var completedTodos = 0;
// get the number of completed todos.
this.todos.forEach(function (todo) {
if (todo.completed === true) {
completedTodos++;
}
});
this.todos.forEach(function (todo) {
// Case 1: If everything is true, make everything.
if (completedTodos === totalTodos) {
todo.completed = false;
// Case 2: Otherwise, make everything true.
} else {
todo.completed = true;
}
});
}
};
var handlers = {
addTodo: function () {
var addTodoTextInput = document.getElementById('add-todo-text-input');
todoList.addTodo(addTodoTextInput.value);
addTodoTextInput.value = '';
view.displayTodos();
},
changeTodo: function (position) {
var changeTodoTextInput = document.getElementById('change-todo-text-input');
todoList.changeTodo(position, changeTodoTextInput.value);
changeTodoTextInput.value = '';
view.displayTodos();
},
deleteTodo: function (position) {
todoList.deleteTodo(position);
view.displayTodos();
},
toggleCompleted: function (position) {
todoList.toggleCompleted(position);
view.displayTodos();
},
toggleAllButton: function () {
todoList.toggleAll();
view.displayTodos();
}
};
var view = {
displayTodos: function () {
var todosUl = document.querySelector('ul');
todosUl.innerHTML = '';
todoList.todos.forEach(function (todo, position) {
var todoLi = document.createElement('li');
var todoTextWithCompletion = '';
if (todo.completed === true) {
todoTextWithCompletion = todo.todoText;
todoLi.classList.add('item-completed');
} else {
todoTextWithCompletion = todo.todoText;
}
todoLi.id = position;
todoLi.textContent = todoTextWithCompletion;
todoLi.appendChild(this.createEditButton());
todoLi.appendChild(this.createToggleButton());
todoLi.appendChild(this.createDeleteButton());
todoLi.appendChild(this.createSaveButton());
todosUl.appendChild(todoLi);
}, this);
},
createDeleteButton: function () {
var deleteButton = document.createElement('button');
deleteButton.textContent = '\u2715';
deleteButton.className = 'delete-button';
return deleteButton;
},
createToggleButton: function () {
var toggleButton = document.createElement('button');
toggleButton.textContent = '\u2713';
toggleButton.className = 'toggle-button';
return toggleButton;
},
createSaveButton: function () {
var saveButton = document.createElement('button');
saveButton.textContent = 'Save';
saveButton.className = 'save-button';
return saveButton;
},
createEditButton: function () {
var editButton = document.createElement('button');
editButton.textContent = '\u270E';
editButton.className = 'edit-button';
return editButton;
},
setUpEventListeners: function () {
var todosUl = document.querySelector('ul');
todosUl.addEventListener('click', function (event) {
// Get the element that was clicked on.
var elementClicked = event.target;
// Check if elementClicked is a delete button.
if (elementClicked.className === 'delete-button') {
handlers.deleteTodo(parseInt(elementClicked.parentNode.id));
} else if (elementClicked.className === 'toggle-button') {
handlers.toggleCompleted(parseInt(elementClicked.parentNode.id));
} else if (elementClicked.className === 'save-button') {
handlers.changeTodo(parseInt(elementClicked.parentNode.id));
} else if (elementClicked.className === 'edit-button') {
}
});
}
};
view.setUpEventListeners();
body {
font-family: Helvetica, sans-serif;
font-size: 25px;
background: rgb(236, 236, 236);
}
h1 {
color: rgb(255, 255, 255);
text-align: center;
font-family: Helvetica, sans-serif;
font-size: 50px;
text-transform: uppercase;
background: rgb(48, 48, 48);
position: relative;
}
.container {
margin: auto;
width: 50%;
}
ul {
list-style: none;
padding:0px;
margin: 10px;
}
.add-button {
background-color: rgb(68, 165, 230); /* Blue */
border: none;
color: white;
margin:auto;
padding: 15px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
border-radius: 5px;
width:20%;
}
.add-button:hover {
background-color :rgb(53, 127, 177); /* Green */
color: white;
}
.save-change-button {
background-color: rgb(68, 165, 230); /* Blue */
border: none;
color: white;
margin:auto;
padding: 15px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
border-radius: 5px;
width:20%;
}
.save-change-button:hover {
background-color :rgb(53, 127, 177); /* Green */
color: white;
}
.toggle-all-button {
background-color: rgb(38, 156, 38); /* Green */
border: none;
color: white;
margin: 10px 0;
padding: 15px 32px;
text-align: center;
text-decoration: none;
font-size: 16px;
border-radius: 5px;
width: 100%;
}
.toggle-all-button:hover {
background-color : rgb(36, 114, 36); /* Green */
color: white;
}
.edit-button {
background-color: rgb(219, 208, 50); /* Green */
border: none;
color: white;
padding: 0;
text-align: center;
text-decoration: none;
font-size: 18px;
border-radius: 5px;
width: 25px;
height: 25px;
margin: 0 0 0 10px;
}
.edit-button:hover {
background-color: rgb(185, 175, 26); /* Green */
color: white;
}
.toggle-button {
background-color: rgb(38, 156, 38); /* Green */
border: none;
color: white;
padding: 0;
text-align: center;
text-decoration: none;
font-size: 18px;
border-radius: 5px;
width: 25px;
height: 25px;
margin: 0 0 0 10px;
}
.toggle-button:hover {
background-color: rgb(36, 114, 36); /* Green */
color: white;
}
.delete-button {
background-color: rgb(168, 44, 44); /* Green */
border: none;
color: white;
margin: 0 0 0 10px;
padding: 0;
text-align: center;
text-decoration: none;
font-size: 18px;
border-radius: 5px;
width: 25px;
height: 25px;
}
.delete-button:hover {
background-color :rgb(128, 31, 31); /* Green */
color: white;
}
.save-button {
background-color: rgb(219, 208, 50); /* Green */
border: none;
color: white;
padding: 0;
text-align: center;
text-decoration: none;
font-size: 18px;
border-radius: 5px;
width: 55px;
height: 25px;
margin: 0 10px;
}
.save-button:hover {
background-color :rgb(185, 175, 26); /* Green */
color: white;
}
.add-input {
margin: 10px 0;
padding: 6px 0;
text-align: center;
font-family: Arial, Helvetica, sans-serif;
font-size: 18px;
width: 78%;
}
.edit-input {
margin: 10px 0;
padding: 6px 0;
text-align: center;
font-family: Arial, Helvetica, sans-serif;
font-size: 18px;
width: 78%;
}
.item-completed {
text-decoration: line-through;
}
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
color: rgba(209, 209, 209, 0.555);
font-family: 'Times New Roman', Times, serif;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Todo List</title>
<link href="index.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="container">
<h1>Todo List</h1>
<div>
<input id="add-todo-text-input" class="add-input" placeholder="Add a New Todo to Your List" type="text">
<button class="add-button" onclick="handlers.addTodo()">Add</button>
</div>
<ul>
</ul>
<div id="edit-todo"">
<input id="change-todo-text-input" class="edit-input" placeholder="Add the Changes Your Want to Make" type="text">
<button class="save-change-button">Save</button>
</div>
<div id="toggle-all"">
<button class="toggle-all-button" onclick="handlers.toggleAllButton()">Toggle All</button>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
You can add a common class to both blue and yellow buttons, and attach a click event by the class name like below
$(".custom_save_button").on("click", function() {
//your code
});
Since you are creating that button, sharing the same class won't just work as expected, instead use delegated events which allow you to attach events on new elements added to the DOM
Add a common class for both and then add an event listener for that class using event delegation.
For this example Let's suppose you chose the class name: stack_class
//I added this function for you to be able to know if an element has a class
function hasClass( target, className ) {
return new RegExp('(\\s|^)' + className + '(\\s|$)').test(target.className);
}
//you could change body to the closest parent's selector both buttons share
document.querySelector('body').addEventListener('click', function(event) {
var clickedElement = event.target;
if(hasClass(clickedElement, "stack_class")) {
//create your functionality for both buttons here
}
});
If you assign a common class to both buttons, then you can add the same event listener to all buttons that have that class. Here is a simple example:
var saveButton = document.createElement('button');
saveButton.textContent = 'Save';
saveButton.className = 'save-button yellow-button';
body = document.querySelector('body');
body.appendChild(saveButton);
buttons = document.getElementsByClassName('save-button');
for (var i = 0; i < buttons.length; i += 1) {
buttons[i].addEventListener('click', function (event) {
alert('Hello!');
});
}
.yellow-button {
background: #ffff00;
}
.blue-button {
background: #0000ff;
}
<button class="save-button blue-button">Save</button>

Aligning items in a table

I made a "To-List" with two icons that animate on the side. the icon on the right is not in the table. So when animating you can see it moving beyond the table. I can't understand why? any help please?
Thank you!
Hi, here is the fiddle:
https://jsfiddle.net/rggo2tmv/
As you can see, the garbage-bin icon disappears inside the table while the other icon (on the right) continues outside the table.
HTML:
<!DOCTYPE html>
<html>
<head>
<title>To-Do List Project</title>
<!-- local css file sheet-->
<link rel="stylesheet" type="text/css" href="assets\css\todo.css">
<!-- Local JQuery js file-->
<script type ="text/javascript" src="assets/js/lib/jquery-3.1.0.min.js"></script>
<!-- googel fonts -->
<link href='https://fonts.googleapis.com/css?family=Roboto:400,700' rel='stylesheet' type='text/css'>
<!-- howel sounds -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.0.0/howler.core.min.js"></script>
<!-- Paper -->
<script type="text/javascript" src="papaer\dist\paper-full.js"></script>
<script type="text/paperscript" canvas="myCanvas">
<!-- two numbers are placing, last number is a radious-->
var circles = [];
var colors = ['blue', 'red', 'orange', 'purple'];
<!-- //DEFINING AN OBJECT -->
var keyData = {
a: {
color: 'purple',
},
b: {
color: 'green',
},
c: {
color: 'yellow',
},
d: {
color: 'orange',
},
e: {
color: 'NavajoWhite',
},
f: {
color: 'yellow',
},
g: {
color: 'orange',
},
h: {
color: 'grey',
},
i: {
color: 'SpringGreen',
},
j: {
color: 'black',
},
k: {
color: 'white',
},
l: {
color: 'darkgrey',
},
m: {
color: 'darkblue',
},
n: {
color: 'darkblue',
},
o: {
color: 'yellow',
},
p: {
color: 'cyan',
},
q: {
color: 'Maroon',
},
r: {
color: 'Red',
},
s: {
color: 'pink',
},
t: {
color: 'Salmon',
},
u: {
color: 'cyan',
},
v: {
color: 'FireBrick',
},
w: {
color: 'Tan',
},
x: {
color: 'Brown',
},
y: {
color: 'Olive',
},
z: {
color: 'YellowGreen',
},
};//closes keyData
function onKeyDown(event) {
if(keyData[event.key]){ //if key is defined
keyData[event.key].color;
<!-- will calc the max size of visible canvas-->
var maxPoint = new Point(view.size.width, view.size.height);
<!-- random is between 0 and 0.99 -->
var randomPoint = Point.random();
<!-- so multiplying max and a random decimal nmber will give us random locaiton inside the canvas -->
var point = maxPoint * randomPoint;
var newCircle = new Path.Circle(point, 200);
newCircle.fillColor = keyData[event.key].color;
<!-- adds the circle to the array -->
circles.push(newCircle);
}//if
};
function onFrame(event) {
<!-- // Each frame, change the fill color of the path slightly by
// adding 1 to its hue: -->
for(var i = 0; i<circles.length; i++){
circles[i].fillColor.hue += 1;
circles[i].scale(.955);
};
};
</script>
</head>
<body>
<div id="container">
<h1>To-Do List <button <i class="fa fa-plus" aria-hidden="true"></i> </button></h1>
<input type="text" placeholder="Add New To-Do">
<!-- span is the button and its inside the li which contains the text -->
<!-- added table to each so they won't all aniamte toghther -->
<table>
<tr>
<td><span class="spanLeft"><i class="fa fa-trash"></i></span></td>
<td colspan="2">Hello There</td>
<td><span class="spanRight"><i class="fa fa-check-square-o"></i></span></td>
</tr>
</table>
<table>
<tr>
<td><span class="spanLeft"><i class="fa fa-trash"></i></span></td>
<td colspan="2">Hello There</td>
<td><span class="spanRight"><i class="fa fa-check-square-o"></i></span></td>
</tr>
</table>
<table>
<tr>
<td><span class="spanLeft"><i class="fa fa-trash"></i></span></td>
<td colspan="2">Hello There</td>
<td><span class="spanRight"><i class="fa fa-check-square-o"></i></span></td>
</tr>
</table>
</div>
<canvas id="myCanvas" resize></canvas>
<!-- Javascript -->
<!-- //icons -->
<script src="https://use.fontawesome.com/9430f1a1cb.js"></script>
<!-- local javascript -->
<script type="text/javascript" src="assets/js/todo.js"></script>
</body>
</html>
Javascript:
///// check-off and remove spicific to-do by clicking or restore it to not-done-yet
//will add/remove class "completed" - grey and line-through
$("div").on("click", "span.spanRight", function(){
$(this).parent().parent().toggleClass("completed"); //if class exists will remove and the opposite according to aprent from span.spanRight
});
var sound = new Howl({
src: ['https://raw.githubusercontent.com/jonobr1/Neuronal-Synchrony/master/assets/A/clay.mp3']
});
//click on delete button to remove to-do
$("div").on("click", "span.spanLeft", function(){
//will remove the to-do, which its li is the parent element of the span
$(this).parent().parent().fadeOut(500, function() //this here refers to the span, but now because of parent()
//fadeOut will not remove only hide element, so we add remove()
{$(this).remove();}); //this refers to the parent
event.stopPropagation(); //will stop the toggle to "completed" class
});
/////creation of new to-do
//event on key press. When we click "enter" it will add the new to-do (input)
$("input[type='text'").keypress(function(){ //only if input is 'text' it will select the input
if (event.which === 13){//if "enter" is clicked in input field
//grabbing text from input
var todoText = $(this).val(); //takes value that inside input
//create a new li and add to ul
if( todoText!== ''){
$("div").append("<table>" + "<tr><td><span class='spanLeft'><i class='fa fa-trash'></i></span></td>" +
"<td colspan='2'>" + todoText + "</td>" +
"<td><span class='spanRight'><i class='fa fa-check-square-o'></i></span></td>" +
"</tr></table>");
$("input").val('');
sound.play();
}
}
});
/////Add button
// selecting the icon
$(".fa-plus").on("click", function() {
if ( $("input").val() === "") {
// empty
$("input").focus();
} else { //make it do enter key /simulate an enter key, sends the input value and clears the input field (and value)
var press = jQuery.Event("keypress");
press.ctrlKey = false;
press.which = 13;
$("input").trigger(press);
//wil ladd input value to feild
$("div").append("<table>" + "<tr><td><span class='spanLeft'><i class='fa fa-trash'></i></span></td>" +
"<td colspan='2'>" + $("input").val() + "</td>" +
"<td><span class='spanRight'><i class='fa fa-check-square-o'></i></span></td>" +
"</tr></table>");
$("input").val('');
sound.play();
} //else
$("input").val('');
});
CSS:
canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
/*layer index*/
z-index: -5;
}
body{
height: 100%;
margin: 0px;
background: linear-gradient(to left, #16BFFD , #CB3066);
}
#container {
width: 360px;
/*to center:*/
margin: 200px auto 200px auto;
/*slight black shadow around*/
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
background: #e6f3ff;
/**/
}
tbody, table {
/*removes bulletpoints*/
padding: 0;
border: none;
margin: 0;
width: 100%;
height: 100%;
/*removes annoying border from table that broswer creates*/
border-collapse:collapse;
background-color: white;
}
tr {
color: #666;
height: 40px;
/*centers the text*/
line-height: 40px;
width: 100%;
}
/*every second li will get this background color IMPORTANT*/
tr:nth-child(2n){
background: #f7f7f7;
}
td {
padding: 0;
margin: 0;
height: 100%;
border: none;
width: 20px;
}
/*mae the delete button appear. animated at span*/
tr:hover span{
/*40px so we'll see the icons which were set to 0 at start*/
width: 40px;
opacity: 1.0;
border: rgb(0, 0, 0, 0,);
}
span {
width: 0%;
padding: 0;
margin: 0;
}
.spanLeft {
background: #e74c3c;
height: 40px;
margin-right: 20px;
margin-left: 0px;
float: left;
text-align: center;
color: white;
/*set zero for animation*/
width: 0px;
/* display: inline-block;*/
/*animates*/
transition: 0.5s;
opacity: 1;
}
.spanRight {
background: blue;
height: 40px;
margin-right:0px;
margin-left: 20px;
float: right;
text-align: center;
color: white;
/*set zero for animation*/
width: 0px;
/* display: inline-block;*/
/*animates*/
transition: 0.5s;
opacity: 0;
}
input {
padding: 13px 13px 13px 20px;
font-size: 16px;
background-color: #f7f7f7;
width: 100%;
/*box sizing includes the padd, margin etc*/
box-sizing: border-box;
/*takes a way the small gaps around input*/
border: 3px solid rgba(0,0,0,0);
}
/*pnly when focued on an input*/
input:focus{
background: #fff;
border: 3px solid #2980b9;
outline: none;
}
.completed {
color: grey;
text-decoration: line-through;
}
/*the plus sign*/
.fa-plus{
background: none;
border: none;
float: right;
}
h1 {
color: white;
text-transform: uppercase;
background: #2980b9;
margin: 0;
padding: 10px 20px;
font-size: 24px;
font-weight: normal;
/*a google font*/
font-family: 'Roboto', sans-serif;
}
The icon inside the span element that you animate, doesn't "shrink" with the span as you might expect. It is shown to the right of the 0 width span instead (i.e. it overflows). You have the same effect both on the left and right side which is visible if you change the color of the icons.
Span is an inline element so it normally doesn't have the overflow property but you can use display: inline-block to display it with a given width and height. Use overflow: hidden to hide the icon when squeezing the width of the span element.

Allow Button Click Only Once in Meteor

In my Meteor project, I have two buttons. One button is an upvote button, which adds a point to the score of an entry, while the other is a downvote button, which does the opposite. My site doesn't require login.
How can I restrict it so that any given device can only click either the upvote or downvote button initially, and then if that device decides to change it's vote, it should be able to click only the other button, and so on?
You can use HTML 5 LocalStorage. But it will only work on latest browsers. If you want suppoert for old browsers as well then you might be interested in this question as well. If your user base doesn't use very old browsers then you can do it with LocalStorage like this,
In template's created callback,
Template.yourTemplate.created = function () {
var template = this;
var userVote = null;
if(typeof(Storage) !== "undefined") {
userVote = localStorage.getItem("userVote");
}
template.userVote = new ReactiveVar(userVote); //or you can use Session.setDefault("userVote", userVote)
}
When user clicks on the up or down button
Template.yourTemplate.events({
'click #upButton': function (ev, template) {
localStorage.setItem("userVote", "up");
template.userVote.set("up"); // or Session.set("userVote", "up");
},
'click #downButton': function (ev, template) {
localStorage.setItem("userVote", "down");
template.userVote.set("down"); // or Session.set("userVote", "down");
}
});
Then to disable buttons, you can do something like this in your helpers,
Template.yourTemplate.helpers({
'isUpButtonDisabled': function () {
var template = Template.instance();
var userVote = template.userVote.get(); // or Session.get("userVote");
return userVote === "up";
},
'isDownButtonDisabled': function (ev, template) {
var template = Template.instance();
var userVote = template.userVote.get(); // or Session.get("userVote");
return userVote === "down";
}
});
Update: This answer uses localStorage so that the application can keep track of the user's vote even when user visits the same site at a later date, which was what OP was trying to do, since user can vote without a login.
EDIT: Based on your comment to have different votes for different templates/topics. Assuming you have current topic's id in template's current data. You can do something like this,
In template's created callback,
Template.yourTemplate.created = function () {
var template = this;
template.userVote = new ReactiveVar(null); //or you can use Session.setDefault("userVote", null)
template.autorun(function () {
var data = Template.currentData();
var topicId = data.topicId;
var userVote = null;
if(typeof(Storage) !== "undefined") {
userVote = localStorage.getItem("userVote" + topicId);
}
template.userVote.set(userVote); //or you can use Session.set("userVote", userVote);
});
}
When user clicks on the up or down button
Template.yourTemplate.events({
'click #upButton': function (ev, template) {
var topicId = this.topicId;
localStorage.setItem("userVote" + topicId, "up");
template.userVote.set("up"); // or Session.set("userVote", "up");
},
'click #downButton': function (ev, template) {
var topicId = this.topicId;
localStorage.setItem("userVote" + topicId, "down");
template.userVote.set("down"); // or Session.set("userVote", "down");
}
});
Then to disable buttons, you can do something like this in your helpers,
Template.yourTemplate.helpers({
'isUpButtonDisabled': function () {
var template = Template.instance();
var userVote = template.userVote.get(); // or Session.get("userVote");
return userVote === "up";
},
'isDownButtonDisabled': function (ev, template) {
var template = Template.instance();
var userVote = template.userVote.get(); // or Session.get("userVote");
return userVote === "down";
}
});
It sounds like a regular old radio button should do the trick.
I made some fancier stuff as well, see this CodePen.
Update
Added #4castle's rescind vote function. Nice touch.
Update 2
Per OP's request, the radio buttons are now the arrows.
CodePen 2
html,
body {
box-sizing: border-box;
background: #111;
color: #DDD;
font: 400 16px/1.4'Verdana';
height: 100vh;
width: 100vw;
}
*,
*:before,
*:after {
box-sizing: inherit;
margin: 0;
padding: 0;
border: 0 none hlsa(0%, 0, 0, 0);
outline: 0 none hlsa(0%, 0, 0, 0);
}
fieldset {
margin: 0 1em 1em 1em;
padding: 8px;
border-radius: 9px;
border: 3px double #FF8;
width: 100%;
max-width: 19em;
}
legend {
font: small-caps 700 1.5rem/2"Palatino Linotype";
color: #FD1;
}
/* RadZ */
#radz input.chkrad {
display: none;
}
#radz input.chkrad + label {
color: #EEE;
background: transparent;
font-size: 16px;
}
#radz input.chkrad:checked + label {
color: #0ff;
background: transparent;
font-size: 16px;
}
#radz input.chkrad + label span {
display: inline-block;
width: 18px;
height: 18px;
margin: -1px 15px 0 0;
vertical-align: baseline;
cursor: pointer;
}
#radz input + label span {
background: transparent;
line-height: 100%;
}
input.A + label span:before {
content: '△';
color: #0ff;
font-style: normal;
font-weight: 700;
font-size: 24px;
}
input.A:checked + label span:before {
padding: -5px 15px 5px;
font-size: 16px;
}
input.A:checked + label span:before {
content: '▲';
color: #0ff;
font-style: normal;
font-weight: 700;
font-size: 24px;
}
input.B + label span:before {
content: '▽';
color: #0ff;
font-style: normal;
font-weight: 700;
font-size: 24px;
}
input.B:checked + label span {
padding: -5px 15px 5px;
font-size: 16px;
}
input.B:checked + label span:before {
content: '▼';
color: #0ff;
font-style: normal;
font-weight: 700;
font-size: 24px;
}
input.fade + label span,
input.fade:checked + label span {
-webkit-transition: background 0.7s linear;
-moz-transition: background 0.7s linear;
transition: background 0.7s linear;
}
<fieldset id="radz" name="radz">
<legend>Vote</legend>
<input type='radio' name='rad' id="rad1" class="chkrad A fade" value='1' />
<label for="rad1"><span></span>Up</label>
<br/>
<input type='radio' name='rad' id="rad2" class="chkrad B fade" value='2' />
<label for="rad2"><span></span>Down</label>
<br/>
</fieldset>
// Rescind vote function provided by 4castle
// http://stackoverflow.com/users/5743988/4castle
var selectedRad;
var voteRads = document.querySelectorAll('input[name="vote"]');
for (var i = 0; i < voteRads.length; i++) {
voteRads[i].onclick = function() {
if (selectedRad == this) {
this.checked = false;
selectedRad = null;
} else {
selectedRad = this;
}
};
}
.rad1 + label:after {
content: '△';
}
.rad1:checked + label:after {
content: '▲';
}
.rad2 + label:after {
content: '▽';
}
.rad2:checked + label:after {
content: '▼';
}
<input id="up" type="radio" class="rad1" name="vote">
<label for="up"></label>
<br/>
<label>Vote</label>
<br/>
<input id="down" type="radio" class="rad2" name="vote">
<label for="down"></label>

Categories

Resources