How to remove two custom buttons from the controlBar component - javascript

I've added two custom buttons (for custom chapter navigation) and later in my code I want to delete/hide them. But using the removeChild() only remove one of the two (even by doing it twice)
Adding them work great but it's really the removing where I'm getting in troubles.
This is what I've tried but I can't delete both
var nextChapButton = myPlayer.controlBar.addChild("button",{}, 1);
var nextChapButtonDom = nextChapButton.el();
nextChapButtonDom.innerHTML = ">>";
var prevChapButton = myPlayer.controlBar.addChild("button",{}, 0);
var prevChapButtonDom = prevChapButton.el();
prevChapButtonDom.innerHTML = "<<";
myPlayer.controlBar.removeChild("Button");
//even doing it twice the ">>" button remains
myPlayer.controlBar.removeChild("Button");
And I cant declare "button" and "button2" to differenciate them or I get the following error because it's not videojs a component
Uncaught Error: Component Button2 does not exist
at ControlBar.addChild (video.js:3525)
at loadVideo (load.js:261)
at loadPage (load.js:196)
at startConfig (load.js:171)
at HTMLButtonElement.onclick (load.html:114)

You already had everything you needed to remove the buttons: prevChapButtonDom and nextChapButtonDom. Removing the buttons would be:
nextChapButtonDom.remove();
prevChapButtonDom.remove();
I created a Codepen to show removing the elements via button. Please note I used jQuery for simplicity but it's not in any way required to remove the button elements.

Related

Inserted JS elements disappear after ajax reload

I am using a WP Plugin FacepWP and want to add reset to the dropdown.
I have used JS to create elements and add the function FWP.reset('country_2').
The problem I have is that when I click reset the page reloads (AJAX I think) and I lose the elements I added by JS
$(document).ready(function(){
function addEle() {
var newElement = document.createElement("a")
newElement.className = 'wf-reset'
newElement.onclick = function() { FWP.reset('country_2')}
newElement.textContent='Reset'
var insertReset = document.querySelector('.facetwp-facet-country_2 .fs-dropdown')
console.log(newElement);
console.log(insertReset);
insertReset.appendChild(newElement)
};
window.onload = addEle;
})
I hope for my added elements to stay on click.
I believe FacetWP uses AJAX to filter and reset but it resets my added JS elements also.
Added:
On existing archive (category, tag, shop, ) or search pages, FacetWP
will automatically attempt to add a facetwp-template CSS class around
the listing. During an ajax refresh, FacetWP will only modify content
within that container element. If your pager doesn’t change after a
FacetWP refresh, then the CSS class may need to to be manually placed
so that it surrounds both the listing and pager.
Sounds like I need to find this class and do something with it to make sure ajax reload keeps the JS I added.

Vue add class to element without v-model:class?

I have two elements, that are in two completely different parts of the DOM. And I'm trying to connect the two, so when you hover one element, the other one shows an effect.
The first element is in a component and is being displayed with code like this inside a component:
<button #mouseover="$emit( 'event-hovered', event.id )" #mouseout="$emit( 'event-not-hovered' )">
Button text
</button>
The second element is being generated using code from an AmCharts-demo:
createCustomMarker: function (image) {
var element = document.createElement('button');
element.className = 'map-marker the-id-' + image.id;
element.title = image.title;
element.style.position = 'absolute';
element.dataset.target = "#id" + image.id;
element.setAttribute('data-toggle', 'modal');
image.chart.chartDiv.appendChild(element);
return element;
}
As can be seen, then I've made a #mouseover that emits the id back to he main instance. In the main instance, then I have a method that finds the second element. But I do that using regular javascript, since I've had issues rewriting that createCustomMarker-function, so both Vue and AmCharts grasps what's going on. But this means that I can't add a class to the second elements (generated by createCustomMarker), the conventional v-model:class-way. I tried doing this in a method in the main instance:
eventHovered: function( elementId ){
let markerWithId = document.getElementById( 'id' + elementId );
markerWithId.classList.add("event-hovered");
console.log( markerWithId );
}
When I console.log the markerWithId, then I can see that that has the added class (event-hovered). But that doesn't appear on the screen, and I assume that's because Vue is controlling the DOM.
So how do I submit the element back to the DOM?
And is this a stupid way of doing this?
Try calling the validateNow() function after you edit the class on the marker.
As seen here:
https://docs.amcharts.com/3/javascriptcharts/AmCoordinateChart
From the Docs:
This method should be called after you changed one or more properties of any class. The chart will redraw after this method is called.Both attributes, validateData and skipEvents are optional (false by default).

Trigger a fade when swapping between classes using jQuery

I have following code working so far: JSFIDDLE DEMO
The relevant JS is here:
// Define classes & background element.
var classes = ['bg1','bg2','bg3','bg4'],
$bg = document.getElementById('blah');
// On first run:
$bg.className = sessionStorage.getItem('currentClass') || classes[0];
// On button click:
$('.swapper').mousedown(function () {
// (1) Get current class of background element,
// find its index in "classes" Array.
var currentClassIndex = classes.indexOf($bg.className);
// (2) Get new class from list.
var nextClass = classes[(currentClassIndex + 1)%classes.length];
// (3) Assign new class to background element.
$bg.className = nextClass;
// (4) Save new class in sessionStorage.
sessionStorage.setItem('currentClass', nextClass);
});
For my purposes, this functionally working great -- I can click a single button to continually swap between those four classes while also storing the current class to sessionStorage, so that when I click links on my website, the currentClass is loaded right away. (Note: on my website the setup is the same, but the classes bg1, bg2, bg3, and bg4 contain background images.)
What I'd like it to do:
When swapping from one class to another, I'd like it to do a quick/short cross-fade. Right now it just snaps from one class/background to another.
My thinking was: is there a way I can trigger a CSS class transition or animation that contains the fade, perhaps as a parent class? I know there's a jQuery fade function, but I haven't been able to get it working with my setup so that it triggers on mouseClick.
Here's an updated jsfiddle based on your comment where you said you've sort of having it work.
I've added the timeout functions
setTimeout(function(){$bg.className = nextClass}, 500);
setTimeout(function(){$($bg).fadeIn(500)}, 500)
The first timeout makes it so that the image is swapped right after the first image fades out. The second timeout gives it a bit of time to load in so it's not so jittery.
You can play with the }, 500); number to get it timed just like you want, 500 is half a second, 1000 is a second etc.

Can't understand Javascript eventhandler with for loop code

I'm trying to learn JavaScript and I saw a code to change the css style of a web page depending on the button you press.
I can't understand why or how a for loop indicate witch button was press. Here is the javascript part:
var buttons = document.getElementsByTagName("button");
var len = buttons.length;
for (i = 0; i < len; i++) {
buttons[i].onclick = function() {
var className = this.innerHTML.toLowerCase();
document.body.className = className;
};
}
http://jsfiddle.net/qp9jwwq6/
I looked on the net and w3 school but they don't explain that code with a for loop. Can someone explain it to me?
Thank you
Lets break it down.
First we need to have access to the DOM element on the page, so we do that by using a method on the document itself which will return the element we want to manipulate.
var buttons = document.getElementsByTagName("button");
The buttons var will be a list of ALL the buttons on the page. We want to do something with all of them, so first we cache the length of the list, i.e, count how many buttons we have.
var len = buttons.length;
Then we basically say: set i to 0, and step it up one until its equal to the number of buttons we have.
for (i = 0; i < len; i++) {
Now, to access one button from the list, we need to use the brackets notation. So buttons[0] is the first element, buttons[1] is the second, etc. Since i starts at 0, we put i in the brackets so that on each iteration it will access the next button in the list.
buttons[i].onclick = function() {
var className = this.innerHTML.toLowerCase();
document.body.className = className;
};
}
This is equivalent of doing:
buttons[0].onclick = function() {
var className = this.innerHTML.toLowerCase();
document.body.className = className;
};
buttons[1].onclick = function() {
var className = this.innerHTML.toLowerCase();
document.body.className = className;
};
buttons[2].onclick = function() {
var className = this.innerHTML.toLowerCase();
document.body.className = className;
};
// etc.
But of course that is super inefficient, and we may not know how many buttons the page has. So we get all the buttons there, find out how many there are, then go through each button and assign an event handler to it along with a new class.
Now, looking at the onclick handler itself we can see that it first finds the HTML within the button being clicked, turns it into lowercase letters, and assigns it to a variable:
var className = this.innerHTML.toLowerCase();
By using this we're ensuring that each button will know to get it's own innerHTML when clicked. We're not tracking which button is which, we're just telling each button to check it's own content.
Then what it does is change the class of the body HTML element to whatever it is that we just parsed
document.body.className = className;
So say you have something like
<button>success</button>
<button>failure</button>
<button>warning</button>
Clicking the first button would set the <body> element's class to success, clicking the second would set it to failure, and the third would set it to warning.
First line saves all buttons in a variable called buttons. This is actually an array since there can be several buttons on the page. Then you iterate through each button and define a function which should be executed onclick. Lets say you have 2 buttons then it will be buttons[0] and buttons[1] which get the function.
Firstly, speaking generally, the underlying basis for this code is a little wonky and unusual and non-robust, so don't anticipate that you're on the brink of learning any powerful insight into JavaScript or code design.
On to the answer:
The for-loop does not "indicate" which button was pressed. Rather, it loops through every button element on the page and assigns the exact same function definition to the onclick attribute of each element. The code that ends up running when a particular button element is clicked (here I'm talking about the function body) assigns a CSS class to the body element by assigning to document.body.className.
Your question is asking how the function knows which class name to assign to document.body.className. The function grabs the class name from the innerHTML of the button element, which is accessible as this.innerHTML (because in an event handler, this is a reference to the element on which the triggering event occurred). The HTML <button> element is a little bit special, in that, although it is generally a simple-looking button, it is also a non-leaf node, meaning it contains its own HTML. You can put a lot of things in there, but in this example, they just have a plain text node which consists of exactly (or nearly exactly) the class name (Normal for one and Changed for the other). That's how the function can get a CSS class name that is specific to that button; it grabs it from the text inside the clicked <button> element.
I said "nearly exactly" back there because there's actually a letter-case difference between the button text and the actual CSS classes they've defined in the CSS rules (which are normal and changed). That's why they have to lower the letter-case of the extracted button text (toLowerCase()) before assigning the class name. CSS classes are case-sensitive (see Are CSS selectors case-sensitive?).
As I said, this is unusual code. It is rather inadvisable to create a mapping (especially an inexact mapping!) between plain HTML text and code metadata (CSS classes in this case).

Dojo destroy MenuItems on DropDownButton

I have the following markup:
<button dojoType="dijit.form.DropDownButton" dojoAttachPoint="labels" label="Labels">
<div dojoType="dijit.Menu" dojoAttachPoint="labelsMenu"></div>
</button>
I am adding MenuItems programatically and it works fine for the first time. But when I want to refresh I get an error: Tried to register widget with id==16 but that id is already registered. I have tried the following code to clear but it's not working:
var labels = dijit.findWidgets(this.labels);
dojo.forEach(labels, function (l) {
l.destroyRecursive();
});
dojo.empty(dojo.byId(this.labels));
I have also try the same thing for labelsMenu to empty it but no luck. Is there any other way to get rid of all children when reloading data or am missing something?
I have solved it and here's what I did:
var menuChildren = dijit.byId(this.labelsMenu).getChildren();
if (menuChildren.length > 0){
dojo.forEach(menuChildren, function(mc){
mc.destroyRecursive();
});
}
In your code you call dojo.empty on the labels. dojo.empty() empties the element in the DOM but keeps the original element. So try calling dojo.empty on the dijit menu instead.
dojo.empty(dojo.byId("labelsMenu"));
For reference, in a fully baseless application, the dom-construct module is used.
require(["dojo/dom-construct"], function(domConstruct){
// Empty node's children byId:
domConstruct.empty("someId");
});

Categories

Resources