KnockoutJS add static and dynamic class name using css property - javascript

I want to add a dynamic classname which will come from javascript based on some check. But one class navigate-forward is there which is also displayed based on some check. How to combine both?
Following is my code -
<span class="menu-item" data-bind="text: data.description,
css: {
'navigate-forward': !child.action,
child.className //I tried something like this which doesn't work
}"></span>
child.className will have a value based on some check in javascript code. And whatever value it gives I want to add that class to this span.
Ex. if child.className is tooltip then that class should be added to the span.
output
<span class="menu-item navigate-forward tooltip">Menu item</span>

The css: binding only accepts a list of classes and whether to apply them or not. You could use:
<div data-bind="attr: { 'class': MyPropertyName }" class="initialClass"></div>
But this would overwrite any pre-existing classes (initialClass) on the element.
Take a look at https://github.com/knockout/knockout/wiki/Bindings---class where there is a custom binding handler that allows you to specify a dynamic class:
<div class="initialClass" data-bind="class: MyPropertyName"></div>
This solution will combine the existing class attribute with the MyPropertyName property.

function vm(){
var self = this;
self.className = ko.observable("class2");
}
(function(){
var viewModel = new vm();
ko.applyBindings(viewModel);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<label class="class1" data-bind="css:className">Your Element</label>

You can also use the style and css bindings with an object that holds all your styles and classes instead of using individual class names. This allows for a more programmatic approach.
function viewModel(){
var self = this;
this.description = ko.observable('placeholder text');
this.useBlue = ko.observable(false);
this.borderClass = ko.observable("red-border");
this.classes = ko.pureComputed(function(){
var obj = {
'blue-background': self.useBlue()
};
obj[self.borderClass()] = true;
return obj;
});
}
ko.applyBindings(new viewModel());
.blue-background {
background-color: lightblue;
}
.red-border {
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<span class="menu-item" data-bind="text: description, css: classes"></span>
<br/>
<input type="button" data-bind="click: function(){ useBlue(!useBlue()) }" value="toggle" />

Related

How to update data attribute using JQuery?

I am trying to use JQuery to update a data attribute after clicking on a button.
Please take a look at what I have tried below.
When I click on the div with class previous-wrapper, the whole block is well updated, and the data-nb-attribute get the correct value.
But, when I click on this div for the second time, data-nb-attribute gets the value NaN..
Is there another way to dynamically update and retrieve the value of this attribute?
$(function(){
$(document).on('click','.previous-wrapper',function(){
var get_nb = $(this).find('.previous');
get_nb = get_nb.data("nb");
get_nb = parseInt(get_nb)
//Dom to update
arr_left = $('<i/>', {
className: 'fa-solid fa-arrow-left'
});
previous = $('<div/>', {
className: 'previous',
'data-nb': get_nb-5,
html: "Previous"
});
//Question 2. How to append previous to arrow_left
$(".previous-wrapper").html(previous);
});
});
.previous-wrapper{
cursor: pointer;
background:red;
width:100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="previous-wrapper">
<i class="fa-solid fa-arrow-left"></i>
<span class="previous" data-nb="100">Previous</span>
</div>
I would also like to know how to add multiple DOM created by JQuery.
You're overwriting the HTML with an invalid attribute of "classname" instead of "class", which means on the second interation $('.previous') won't match anything.
Corrected version of your code:
$(document).on('click', '.previous-wrapper', function() {
var get_nb = $(this).find('.previous');
get_nb = get_nb.data("nb");
get_nb = parseInt(get_nb)
//Dom to update
arr_left = $('<i/>', {
class: 'fa-solid fa-arrow-left'
});
previous = $('<div/>', {
class: 'previous',
'data-nb': get_nb - 5,
html: "Previous"
});
// including both elements at once:
$(".previous-wrapper").html([arr_left, previous]);
console.log($('.previous-wrapper').html())
});
.previous-wrapper {
cursor: pointer;
background: red;
width: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="previous-wrapper">
<i class="fa-solid fa-arrow-left"></i>
<span class="previous" data-nb="100">Previous</span>
</div>
It would be much, much simpler, however, to simply update the one attribute you want to update, instead of rewriting all the HTML every click:
$(document).on('click', '.previous-wrapper', function() {
let el = $(this).find('.previous')
// update the data attribute using .attr() instead of .data() because jQuery handles .data internally; it's not reflected in the DOM
el.attr('data-nb', Number(el.attr('data-nb')) - 5);
console.log($('.previous-wrapper').html())
});
.previous-wrapper {
cursor: pointer;
background: red;
width: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="previous-wrapper">
<i class="fa-solid fa-arrow-left"></i>
<span class="previous" data-nb="100">Previous</span>
</div>

Add/Remove element-binding in Bindinghandler - knockout

Hello I have created a list and sliced it up and added pagingnation.
All works good but I would like the user to be able to disable pagingnation and just use regular scroll.
My html mark-up looks somewhat like this atm.
<div data-bind="event: { mousewheel: ScrolledPagingnation }">
</div>
Im thinking a custom handler is the right tool for the job? but havent really have any succes adding/removing the event..
<div data-bind="toggleScroll: EnablePagingnation">
</div>
EnablePagingnation is just an observable toggeling a boolen.
How can I implement adding/removing of the 'event object on my element?
Any other suitable approach is welcome aswell.. :)
ko.bindingHandlers.toggleScroll = {
update: function (element, valueAccessor, allBindings) {
var value = valueAccessor();
if (ko.unwrap(value) === true) {
//Pseudo Code
element add "event: { mousewheel: ScrolledPagination }"
} else {
//Clean the Binding
ko.cleanNode(element);
}
}
};
Don't use cleanNode. Ever.
You don't even need a bindingHandler. Just use an expression for the event handler. I used the click event in the snippet below.
vm = {
active: ko.observable(false),
v: ko.observable(1),
addToV: function() {
vm.v(vm.v() + 1);
}
};
ko.applyBindings(vm);
#area {
height: 10rem;
width: 10rem;
background-color: lightgreen;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div id="area" data-bind="event: {click: active() ? addToV : null}"></div>
Activate:
<input type="checkbox" data-bind="checked: active" />
<div data-bind="text: v"></div>

get parent div id onclick of icon

On click of fa-eye icon I want to focus/highlight only that div.
Html:
<i style="float: right; margin: 8px; cursor: pointer;" class="fa fa-eye" ng-click="focus()"></i>
JS:
$scope.focus = function($element) {
$('#focus-overlay').toggleClass("focus-overlay");
$('#last').toggleClass("widget-focus-enabled");
};
In place of id="last" I have to find the id on click of icon and then need to add class..
I tried : $($event.target).parent() but not able to get the result.
Demo : http://plnkr.co/edit/HvTRdjNVdmHjnyG41O4F?p=preview
Please help.
You can use this for getting the current object,
ng-click="focus(this)"
Then in the function,
$scope.focus = function($element) {
var parent= $($element).closest("div");
$('#focus-overlay').toggleClass("focus-overlay");
$('#last').toggleClass("widget-focus-enabled");
};
.closest("div") will get the parent div. Advantage of closest() over parent() is it can traverse multiple level.
Just pass $event property of angularjs in ng-click method.
ng-click="focus($event)"
In your method do so.
$scope.focus = function($element) {
var parent= $($element.target).closest("div");
$('#focus-overlay').toggleClass("focus-overlay");
$('#last').toggleClass("widget-focus-enabled");
};
if you read this thread:
Automatically pass $event with ng-click?
you will see the comment by zeroflagL, which i just upvoted,
you are trying to modify a visual component in a controller,
which is not what is the intention of this handler
it is further supported by the angular documentation:
'Controllers should contain only business logic. Putting any presentation logic into Controllers significantly affects its testability. '
https://docs.angularjs.org/guide/controller
there is nothing stopping you from using plain old javascript here
i have added a script block that applies a style, not to the direct
parent but a few up
here is your modified plunker,
http://plnkr.co/edit/0x4ZqKoQcQLHXMMWtLJD
but in essence here are the additions:
index.html:
<script>
var _handleclick = function(ele) {
ele.parentElement.parentElement.parentElement.style.backgroundColor = 'red';
}
</script>
template.html:
<i style="float: right; margin: 8px; cursor: pointer;" class="fa fa-eye" onclick="_handleclick(this)" ng-click="focus()"></i>

Change class name of a img tag in jquery

I have to change a class name in my img tag
<img src="img/nex2.jpeg" class="name">
Now on a hover function in jquery I want to add a class name to it.
So after hovering this tag should look like
<img src="img/nex2.jpeg" class="name secondname">
And once again on removal it should change to
<img src="img/nex2.jpeg" class="name">
Here is what you need:
jQuery(function($) {
$('img.name').hover(function() {
$(this).addClass('secondname');
},
function() {
$(this).removeClass('secondname');
});
});
Or better to use CSS:
img.name:hover {
// do your styling here
}
$("img").hover(
function() {
$( this ).toggleClass('second');
}, function() {
$( this ).toggleClass('second');
}
);
.second {
border: 2px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="http://lorempicsum.com/futurama/200/200/1" class="name">
Answer:
The Complete Code in JavaScript goes like this:
This gives you complete freedom to do any styling using JavaScript and is faster than jQuery.
<script type="text/javascript">
function addClass()
{
document.getElementById("apple").className += " secondname";
}
function removeClass()
{
//replaces all classes with initial class
document.getElementById("apple").className = "name";
}
window.onload = function()
{
document.getElementById("apple").addEventListener( 'mouseover' , addClass );
document.getElementById("apple").addEventListener( 'mouseout' , removeClass );
}
</script>
...
<img src="img/nex2.jpeg" id="apple" class="name">
Remember that using CSS is fastest:
img.name:hover
{
//paste all styles of class name secondname
}
This way you don't have to create two classes. Only name class is enough.
Rest goes with your styling, it's up to you how you style.

Remove Dynamically Added Fields with Javascript

I have a form where I am cloning the initial input fields as a template to allow the user to add as many options as they need to. Adding new fields works fine, but when attempting to remove them, the first one works as expected but all generated fields cannot be removed.
My knowledge of JS is very poor but I would assume that setting it to remove the parent should be the correct operation.
<script type="text/javascript">
$(function()
{
var template = $('#inventoryItems .inventory:first').clone(),
inventoryCount = 1;
var addInventory = function()
{
inventoryCount++;
var inventory = template.clone().find(':input').each(function()
{
var newId = this.id.substring(0, this.id.length-1) + inventoryCount;
$(this).prev().attr('for', newId); // update label for (assume prev sib is label)
this.name = this.id = newId; // update id and name (assume the same)
}).end() // back to .attendee
.attr('id', 'inv' + inventoryCount) // update attendee id
.appendTo('#inventoryItems > fieldset'); // add to fieldset
};
$('.btnAddInventory').click(addInventory); // attach event
});
$(function()
{
var removeInventory = function()
{
$(this).parent().remove();
};
$('.btnRemoveInventory').click(removeInventory); // attach event
});
</script>
HTML:
<div id="inventoryItems" class="inventoryItems" style="margin:0; padding:0;">
<fieldset style="width:62%; float:left; margin-left: 19%;">
<label>Inventory</label>
<div id="inv1" class="inventory">
<select name="invItem1" style="width:92%;">
<?php
$invItem_values = array("id", "name");
display_options_list($dp_conn, $invItem_values, "inventory", "id");
?>
</select>
<input class="btnRemoveInventory" type="button" style="background: url(images/icn_trash.png) no-repeat; cursor:pointer; border: none;">
</div>
</fieldset><div class="clear"></div>
<!-- Add Inventory Button -->
<div style="width:62%; margin:0; padding:0; float: right; margin-right: 19%">
<input class="btnAddInventory" type="button" value="Add Item" style="float: right;">
</div><div class="clear"></div>
</div>
Attaching events via click() (or any other shortcut event handler) only works with elements which are available on load of the page. Instead, because you are appending elements dynamically, you need to use a delegated event handler. Change this:
$('.btnRemoveInventory').click(removeInventory)
To this:
$('#inventoryItems').on('click', '.btnRemoveInventory', removeInventory)
This is attaching the event to the nearest static element, #inventoryItems, and then filters the events raised to see if the target matches .btnRemoveInventory.

Categories