Handling focus on a toggle button - javascript

I am trying to keep the focus on the toggle button after it gets pressed.
Right now, when I click on the button, the focus jumps to the top of the page. I am not sure what I am doing wrong.
Here is the code:
HTML
<button ng-if=“test” ng-click=“deactivate()">Deactivate</button>
<button ng-if=“!test” ng-click="activate()”>Activate </button>
JS
$scope.activate = function () {
var activateButton = document.activeElement;
if ($scope.some.length) {
$scope.enableSome($scope.some, true);
}
activateButton.onclick = function () {
activateButton.focus();
};
};
$scope.deactivate = function () {
var activateButton = document.activeElement;
if ($scope.some.length) {
$scope.enableSome($scope.some, false);
}
activateButton.onclick = function () {
activateButton.focus();
};
};

You actually have two buttons that are added/removed from the DOM based on the ng-if condition (documentation).
Your button is not getting focused because the activate button is getting removed while the deactivate button is added, and vice versa.
We can refactor the two buttons into one using a toggleActivation() method.
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.test = false;
$scope.some = [1, 2, 3];
$scope.enableSome = function(some, activate) {
//Do whatever
console.log('enableSome called with activate = ' + activate);
}
$scope.toggleActivation = function() {
//Toggle the state
$scope.test = !$scope.test;
if ($scope.some.length) {
$scope.enableSome($scope.some, $scope.test);
}
//The button is still focused!
console.log('Focused element: ', document.activeElement);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<button ng-click="toggleActivation()">
{{test ? "Deactivate" : "Activate"}}
</button>
</div>

Related

Why can't I update an input element inside click event?

Why does the input element not get updated?
function route() {
let textfield = {
inputEl: document.querySelector('#textfield'),
setValue: function(str) {
this.inputEl.value = str;
}
};
textfield.inputEl.addEventListener('click', function(event) {
document.body.innerHTML += '<button id="select">Select</button>';
owner(textfield);
});
}
function owner(controller) {
document.querySelector('#select').addEventListener('click', function(event) {
controller.setValue("Hello Universe!");
});
}
route();
I know how to go around this problem but i prefer to use controller.setValue() to update the input.
UPDATED
I have updated the code below - hopefully this is closer to what you are trying to achieve.
I needed to add a container where to place the button (instead of adding it to the body) - so added a wrapper container like this:
<div id="container">
<input type="text" id="textfield" />
</div>
Then, we can append the button to it as a child, like this:
document.getElementById('container').appendChild(btn);
See updated code below
function route() {
let textfield = {
inputEl: document.querySelector('#textfield'),
setValue: function(str) {
this.inputEl.value = str;
}
};
textfield.inputEl.addEventListener('click', function(event) {
// add the button if it's not already in there
if(document.getElementById('select')){
return;
}
let btn = document.createElement('button');
btn.id = 'select';
btn.innerHTML = 'Select';
document.getElementById('container').appendChild(btn);
owner(textfield);
});
}
function owner(controller) {
document.getElementById('select').addEventListener('click', function(event) {
controller.setValue("Hello Universe!");
});
}
route();
<div id="container">
<input type="text" id="textfield" />
</div>

why remove class not working in javascript?

I have tried this before and it worked well but here i dont know...
<div onclick="choose(this)">
<div class="choose">
<button><a>click</a></button>
</div>
</div>
my JavaScript:
function choose(obj) {
obj = obj || document.activeElement;
var res_item = obj.querySelector(".choose");
res_item.classList.add("choosed_item");
var close = obj.querySelector(".choose button a");
close.addEventListener("click", function closemodal() {
if (res_item.classList.contains("choosed_item")) {
res_item.classList.remove("choosed_item");
}
});
}
choose and choosed_item have custom style
This is strange, but if i change remove to add and choose another class it works well !
The event is not updated because its child of onclick function. Thats why I integrated an interval. That will help to update the eventlistener:
function choose(obj) {
obj = obj || document.activeElement;
var interval;
var res_item = obj.querySelector(".choose");
res_item.classList.add("choosed_item");
var close = obj.querySelector(".choose button a");
close.addEventListener("click", function closemodal() {
if (res_item.classList.contains("choosed_item")) {
interval = setInterval(function () {
res_item.classList.remove("choosed_item");
stopInterval();
}, 0);
function stopInterval() {
clearInterval(interval);
}
}
});
}
Hope I could help!

Button firing twice when clicked

If you goto the JSFiddle underneath. Add two items and then press 'complete' on one of the items in the console it logs out the same button twice. I can't figure out why.
What am I doing wrong here! :)
https://jsfiddle.net/7k84p3oz/6/
HTML
<input id="inputAdd" type="text" name="" value="">
<button id="submitItem" type="button" name="button">Add</button>
<!-- Start of list -->
<ul id="listContent"></ul>
<!-- End of list -->
<!-- Start of completed -->
<div id="completed">
<h4>Completed</h4>
</div>
<!-- End of completed -->
JS
$(document).ready(function(){
(function() {
var itemTracker = {
// init
init: function() {
this.bindEvents();
},
// cacheDom
cacheDom: {
inputAdd: $('#inputAdd'),
submitAdd: $('#submitItem'),
listContent: $('#listContent'),
completed: $('#completed')
},
// Add item
addItem: function() {
var itemValue = this.cacheDom.inputAdd.val();
var listItem = $("<li></li>");
var buttonRemove = '<button class="remove">Remove</button>';
var buttonComplete = '<button class="complete">Complete</button>';
listItem.append(itemValue);
listItem.append(buttonRemove);
listItem.append(buttonComplete);
var itemContent = this.cacheDom.listContent.append(listItem);
this.cacheDom.inputAdd.val("");
// Remove item
var remove = $('.remove');
remove.on("click", function(e){
$(e.target).closest("li").hide();
});
var complete = $(".complete");
// Complete item
var completedItem = function(e) {
console.log(this);
// var childParent = $(this).parent();
// var rootParent = childParent.parent();
// var parentId = rootParent.prop('id');
//
// if(parentId === "listContent") {
// $('#completed').append(listItem);
// } else {
// $('#listContent').append(listItem);
// }
};
complete.on("click", completedItem);
},
// Bind Events
bindEvents: function() {
this.cacheDom.submitAdd.on("click", this.addItem.bind(this));
}
};
itemTracker.init();
})();
});
This is because every time you add a new item, you are getting ALL the buttons with class .complete var complete = $(".complete"); and appending an action to them.
Hence, if you add 1 button: it will only trigger once.
If you add 2 buttons: the first one will trigger twice, the second one once.
If you add 3 button: the first one will trigger three times, the second twice and the third once.
etc...
You can fix it by replacing: var complete = $(".complete");
For: var complete = $(listItem).find(".complete")
On line 36.
This will ensure that it only selects the .complete button within the listItem that you are creating at that moment.
The reason is you have bind the class name to click event; meaning the event handler is fired for number of HTML elements which has the class name complete.
Since you have e parameter in your event handler function try to use the e.target which will give the clicked element.
var completedItem = function(e) {
console.log(e.target);
}
In your code, you were using var complete = $(".complete");
to find complete button. Due to this when you add second entry, $(".complete"); will return 2 elements and this will also attach event to the earlier node as well.
What you can do wrap the complete button in jquery like
var buttonComplete = $('<button class="complete">Complete</button>')
and use this buttonComplete to attach click event.
buttonComplete.on("click", completedItem);
$(document).ready(function(){
(function() {
var itemTracker = {
// init
init: function() {
this.bindEvents();
},
// cacheDom
cacheDom: {
inputAdd: $('#inputAdd'),
submitAdd: $('#submitItem'),
listContent: $('#listContent'),
completed: $('#completed')
},
// Add item
addItem: function() {
var index=this.cacheDom.listContent.children().length;
var itemValue = this.cacheDom.inputAdd.val();
var listItem = $("<li></li>");
var buttonRemove = '<button class="remove">Remove</button>';
var buttonComplete = $('<button class="complete">Complete</button>')
listItem.append(itemValue);
listItem.append(buttonRemove);
listItem.append(buttonComplete);
var itemContent = this.cacheDom.listContent.append(listItem);
this.cacheDom.inputAdd.val("");
// Remove item
var remove = $('.remove');
remove.on("click", function(e){
$(e.target).closest("li").hide();
});
var complete = $(".complete");
// Complete item
var completedItem = function(e) {
console.log(this);
// var childParent = $(this).parent();
// var rootParent = childParent.parent();
// var parentId = rootParent.prop('id');
//
// if(parentId === "listContent") {
// $('#completed').append(listItem);
// } else {
// $('#listContent').append(listItem);
// }
};
buttonComplete.on("click", completedItem);
},
// Bind Events
bindEvents: function() {
this.cacheDom.submitAdd.on("click", this.addItem.bind(this));
}
};
itemTracker.init();
})();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<input id="inputAdd" type="text" name="" value="">
<button id="submitItem" type="button" name="button">Add</button>
<!-- Start of list -->
<ul id="listContent"></ul>
<!-- End of list -->
<!-- Start of completed -->
<div id="completed">
<h4>Completed</h4>
</div>
<!-- End of completed -->

Toggle Event Listeners

I am trying to make a function that would allow me to toggle eventListener of an element.
In the example below, I have three buttons: main, on and off. When I click on the on button, the main button becomes functional. After I click off button, the main button should not work anymore (but now it still does).
Now I can achieve a desired behavior by clicking on button for the second time, but I guess it's a bad coincidence and it's not supposed to work that way.
Maybe I should add that I would like to work this out without using jQuery or similar and it needs to be a function, because I am going to use it for a lot of buttons.
(I suspect something with scope causes the problem (clickHandler when calling the function to activate the button is not the same as the clickHandler when calling the function to disable the button), but I can't think of a way to test it.)
// buttons definitions, not important
var mainButton = document.querySelector("#mainButton");
var onButton = document.querySelector("#onButton");
var offButton = document.querySelector("#offButton");
// main function
var toggleButtons = function(toggleVal, button, element) {
var activateButton, clickHandler, disableButton;
// callback function for listener bellow
clickHandler = function() {
document.querySelector(element).classList.toggle("yellow");
};
activateButton = function() {
button.addEventListener("click", clickHandler);
};
disableButton = function() {
button.removeEventListener("click", clickHandler);
};
// when first argument is 1, make the button functional, otherwise disable its functionality
if (toggleVal === 1) {
activateButton();
} else {
disableButton();
}
};
// when onButton is clicked, call main function with arguments
// this works
onButton.addEventListener("click", function() {
toggleButtons(1, mainButton, "body");
});
// this fails to disable the button
offButton.addEventListener("click", function() {
toggleButtons(0, mainButton);
});
.yellow {
background-color: yellow;
}
<button type="button" id="mainButton">mainButton
</button>
<button type="button" id="onButton">onButton
</button>
<button type="button" id="offButton">offButton
</button>
<p>mainButton: toggles background color on click
</p>
<p>onButton: turns on mainButtons's functionality</p>
<p>offButton: supposed to turn off mainButton's functionality</p>
var mainButton = document.querySelector("#mainButton");
var onButton = document.querySelector("#onButton");
var offButon = document.querySelector("#offButton");
var element; // declare the element here and change it from toggleButtons when needed.
function clickHandler() {
document.querySelector(element).classList.toggle('yellow');
}
function activateButton(button) { // You missed this part
button.addEventListener('click', clickHandler);
}
function disableButton(button) { // You missed this part
button.removeEventListener('click', clickHandler);
}
function toggleButtons(value, button) {
if (value === 1) {
activateButton(button); // You missed this part
} else {
disableButton(button); // You missed this part
}
};
onButton.addEventListener('click', function() {
element = 'body'; // you can change it to some other element
toggleButtons(1, mainButton);
});
offButton.addEventListener('click', function() {
element = 'body'; // you can change it to some other element
toggleButtons(0, mainButton);
});
Below code helps to toggle between two functions from an eventListener:
var playmusic=false;
function playSound() {
const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`)
audio.currentTime = 0
audio.play()
playmusic=true;
}
function stopSound() {
const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`)
audio.pause()
playmusic=false;
}
window.addEventListener('keydown',
function(){playmusic?stopSound():playSound()} )

jQuery - Toggle text to change on click

I have a menu button, which when clicked will slide down a div below.
My menu is title "+ Open menu"
When the menu button is clicked my code changes the title to "+ Menu" to indicate that the menu is open.
When the user closes the menu I would like the title to revert back to "- Menu"
This is my HTML which defines the class, test in this case.
<span class="test">+ Open menu</span>
Here is my jQuery function, I cannot figure out how to revert the menu state.
$(document).ready(function () {
$(".widget_head_type").click(function ()
{
$(".widget_body_type").slideToggle("slow");
$(".test").text("- Close menu");
});
});
$(".widget_head_type").click(function () {
$(".widget_body_type").slideToggle("slow");
($(".test").text() === "+ Open menu") ? $(".test").text("- Close menu") : $(".test").text("+ Open menu");
});
jQuery.fn.extend({
toggleText: function (a, b){
var that = this;
if (that.text() != a && that.text() != b){
that.text(a);
}
else
if (that.text() == a){
that.text(b);
}
else
if (that.text() == b){
that.text(a);
}
return this;
}
});
Use as:
$("#YourElementId").toggleText('After', 'Before');
Here is an interesting one based on the http://api.jquery.com/toggle/
HTML
<span class="test">+ Open menu</span>
<span class="test" style="display:none">- Close menu</span>
JS
$(document).ready(function () {
$(".widget_head_type").click(function ()
{
$(".widget_body_type").slideToggle("slow");
$(".test").toggle();
});
Simple, just toggles the all tags with class test whether hidden or visible.
WORKING FIDDLE HERE
I've guessed at your html, and made some notes for alternatives, but you consider the following:
HTML:
<div class="some_parent_class">
<div class="widget_head_type">
<span class="test">+ Menu</span>
</div>
<div class="widget_body_type">
Body
</div>
</div>
JS:
jQuery(function ($) {
$('.widget_head_type').each(function () {
// closures
var $toggle = $(this);
var $parent = $toggle.closest('.some_parent_class');
var $target = $parent.find('.widget_body_type');
var $label = $toggle.find('.test');
var bIsTweening = false;
// OR var $target = $toggle.next('.widget_body_type');
// event methods (closures)
var fClickToggle = function () {
if (!bIsTweening) {
bIsTweening = true;
$target.slideToggle('slow', fToggleCallback);
}
};
var fToggleCallback = function () {
bIsTweening = false;
fSetLabel();
};
var fSetLabel = function () {
var sLabel = $label.text().replace('+', '').replace('-', '');
sLabel = ($target.is(':visible') ? '-' : '+') + sLabel;
$label.html(sLabel);
};
// handle event
$toggle.click(fClickToggle);
$target.hide();
fSetLabel();
});
});
had same issue and this is how i solved it: using your code example.
$(".widget_head_type").click(function () {
$(".widget_body_type").slideToggle("slow");
($(".test").text() == "+ Open menu") ? $(".test").text("- Close menu") : $(".test").text("+ Open menu");
});
use two equal signs for comparison.

Categories

Resources