Is there a way for JavaScript to interact with the DOM on a WordPress page. Or is interaction only possible through jQuery?
Button element in header.php:
<div id="settings" class="special-menu__item btn-settings">
<button class="special-menu__title">
<i style="margin-right: 10px" class="fa fa-cog" aria-hidden="true"></i>
Настройки
</button>
</div>
JavaScript Code:
const settingButton = document.getElementById("settings");
let toggle = false;
settingButton.addEventListener("click", function _f() {
if (toggle === false) {
settingButton.classList.add("active");
settingOpen.classList.add("open");
} else {
settingButton.classList.remove("active");
settingOpen.classList.remove("open");
}
toggle = !toggle;
removeEventListener("click", _f);
});
I was having this issue too.
In the console, I could grab any element I wanted with getElementById or querySelector. But when I would select it in my custom JS code, it would be null.
To get around this, you can just add your code in a load event listener. This way, after the page loads, you can run your code and change the DOM element how you want.
It might not be the most functional thing to watch, but it works.
example:
window.addEventListener('load', () => {
const element = document.querySelector('#elementId');
console.log('element I selected:', element)
})
Related
I am having a strange issue with the bootstrap toolkit inside ngFor. On hover, it is taking some time to display the toolkit title and CSS is not getting applied. Please find the screenshot for the same. And if the toolkit is used outside ngFor, it works fine. It works normally.
Here is my code
.ts
ngOnInit(): void {
jQuery(function() {
(jQuery('[data-toggle="tooltip"]') as any).tooltip();
});
this.getGroupsForBox();
}
async getGroupsForBox() {
this.groups = await this.boxManagementService.findGroupsOfBox(this.hub.id);
}
.html
<div *ngFor="let group of groups">
<span
class="badge badge-info"
data-toggle="tooltip"
data-placement="bottom"
title="{{ group.GroupDescription }}"
>{{ group.GroupName }}</span
>
<span> </span>
</div>
*ngFor is structural directive, it creates html DOM on the fly when get the data. That's how it work, ideally you should get ride of jQuery and use the angular bootstrap library.
How ever you can achieve that, you just need to make sure to execute jQuery method after that *ngFor completed the rendering off all the items in the list. Than only you should do that.
code.ts
ngOnInit(): void {
// right now in ngOnInit, nothing is there in the DOM it doesn't applied to that
// Remove this from here.
// jQuery(function() {
// (jQuery('[data-toggle="tooltip"]') as any).tooltip();
// });
this.getGroupsForBox();
}
async getGroupsForBox() {
this.groups = await this.boxManagementService.findGroupsOfBox(this.hub.id);
// once you know list are populated in html then do that part
// getting the data in TS and rendering in html there will be time difference in ms, use small hack of setTimeout not ideal not recommended but it will do the job
setTimeout(()=>{
jQuery(function() {
(jQuery('[data-toggle="tooltip"]') as any).tooltip();
});
},500);
}
I am trying to add an onClick eventhandler into a material ui and sometimes it is called, sometimes it is not. However, it's working fine with regular buttons
handleClick = (event) => {
const value = event.target.value;
console.log(value);
this.setState({ filtered: this.state.videos.filter(item => {
return item.category === value
})
})
<Button value="java" onClick={this.handleClick} color="primary">Java</Button>
<Button value="React" onClick={this.handleClick} color="primary">React</Button>
<Button value="C#" onClick={this.handleClick} color="primary">C#</Button>
<Button value="javascript" onClick={this.handleClick} color="primary">JavaScript</Button>
when I updated to console.log to get event.target, I got the result shown in the image below
I found the issue, but still don't know how yo fix it. React adds two spans to the Button that have no attribute name, so when I click the button, the function gets called, but not when I click the span
You can use event.currentTarget.value instead of event.target.value.
Material-ui's Button has a nested span inside the button, so when you use event.target.value and the user clicks the span you get the span as event.target, if you'd use event.currentTarget you'd get the element that the event listener is attached to - the button.
See a working example: https://codesandbox.io/s/cocky-cookies-s5moo?file=/src/App.js
Inside your handle click, you could also do:
return (item.category === value || item.category === event.target.innerHTML)
But obviously CD..’s answer is better
Besides relying on currentTarget, you can always curry the parameter to the callback function (imagine you are not passing in static content, but maybe the index of an iteration or some dynamic values stored in an object, etc)
Example
handleClick = (value) => () => {
console.log(value);
this.setState({ filtered: this.state.videos.filter(item => {
return item.category === value
})
})
<Button value="java" onClick={this.handleClick('java')} color="primary">Java</Button>
<Button value="React" onClick={this.handleClick('React')} color="primary">React</Button>
<Button value="C#" onClick={this.handleClick('C#')} color="primary">C#</Button>
<Button value="javascript" onClick={this.handleClick('javascript')} color="primary">JavaScript</Button>
My Joyride works great. It starts after page load. It stops when one clicks the stop button or finishes the tour. My restart link restarts the joyride tour. Only...
Adding the Joyride setting, cookie_monster: true prevents the tour restarting on every visit. Good! Unfortunately, it also prevents the restart link from working. The behavior makes sense. The start function does not know whether it is called on page load or from the link. The link has to use some other method, or set something to bypass the cookie check.
Do you know the magic to enable a user to start the Joyride after it has been hidden by the cookie_monster show-only-first-time device?
Body markup:
<a href='#', data-joyride-restart>tips</a>
<p id='first-stop'>First stop content</p>
<p id='second-stop'>Second stop content</p>
<ol class='joyride-list' data-joyride data-joyride-name='my_name',
data-joyride-autostart='true'>
<li data-id='first-stop', data-text='Next'>
<p>First stop tip</p>
</li>
<li data-id='second-stop', data-text='Next'>
<p>Second stop tip</p>
</li>
<li data-text='End'>
<p>Last stop modal tip</p>
</li>
</ol>
Javascript:
;$(function() {
var tour_root = $('ol[data-joyride]')
if (tour_root !== undefined){
var attr = tour_root.attr('data-joyride-name');
var cookie_name;
if (attr !== undefined){
cookie_name = attr;
} else {
cookie_name = 'joyride';
}
$(document).foundation({
joyride : {
'cookie_monster': true,
'cookie_domain': 'domain.com',
'cookie_name': cookie_name
}
});
attr = tour_root.attr('data-joyride-autostart');
if (attr !== undefined && attr.match(/true/i)) {
$(document).foundation().foundation('joyride', 'start');
}
}
$('a[data-joyride-restart]').on('click', function (e){
e.preventDefault();
$(document).foundation().foundation('joyride', 'start');
});
});
Writing the question helped me work out the trick. (I'll leave it posted because I didn't find any good examples for this behavior.)
$('a[data-joyride-restart]').on('click', function (e){
e.preventDefault();
$(document).foundation({
joyride : {
'cookie_monster': false
}
}).foundation().foundation('joyride', 'start');
});
The code resets the cookie-monster setting before asking Joyride to start.
If there is a better way, please share the love!
I am working on a little project with knockout where i have to simulate the answer to asome questions.
I dynamically build 3 buttons and when i click one i compare the text on it with the correct answer and if it's correct it should become green.., if it's not correct it should become red and the right one should become green..
I was trying to use the binding to css property of knockout, but it seems that the property is not correctly refreshed, even if the computed associated with the css changes
The html:
<ul data-bind="foreach: chosenQuestionAnswers">
<li>
<button data-bind="text: answerText, css: $root.answerStatus(), click: $root.selectButton"></button>
</li>
</ul>
The ko part:
selectedAnswer: ko.observable(),
isAnswerCorrect: ko.observable(),
selectButton: function (value) { my.AppViewModel.isAnswerCorrect(my.AppViewModel.checkIfCorrectAnswer(value.answerText));
},
checkIfCorrectAnswer: function (value) {
return (value == my.AppViewModel.chosenQuestionCorrectAnswer());
},
my.AppViewModel.answerStatus = ko.computed(function () {
var exit = this.isAnswerCorrect() == true ? "highlightRight" : "highlightWrong";
console.log(this.isAnswerCorrect());
console.log(exit);
return exit;
}, my.AppViewModel);
The console.log shows the correct value of the var exit... but the css of the button does not change...
Any idea why?..
Thanks.... I.
you're referencing an old version of KO (2.1), the latest as of today is version is 2.2.1. Your fiddle works when referencing the new version # http://knockoutjs.com/downloads/knockout-2.2.1.js. Here's a fork: http://jsfiddle.net/drdamour/xe2M5/
The dynamic css binding (how you're using it) was only added in 2.2 see http://blog.stevensanderson.com/2012/10/29/knockout-2-2-0-released/
stack won't let me submit without some code so...here some worthless code:
var x = {a:1}
css classes are part of the view, try to keep them out of the ViewModel, it should focus on business logic.
I would do something like
http://jsfiddle.net/hLXbq/
HTML
<button data-bind="css: { valid: valid, invalid: invalid }, click: toggle">Toggle</button>
JS
ViewModel = function () {
this.valid = ko.observable(false);
this.invalid = ko.computed(function () {
return !this.valid();
}, this);
};
Currently I have a Wordpress website that uses Isotope to display all posts in a grid and there is a fixed navigation that is used for filtering the post categories.
I am trying to add some Javascript or Jquery to scroll to the top of the page when a navigation item is clicked - so it filters the category and also scrolls to the top of the page.
I have been trying different examples for a while and cannot figure it out.
I was hoping someone might be able to point me in the right direction.
Currently my navigation looks like this:
<div class="menuContainer right">
<ul id="options" class="option-set">
<li>Editorial</li>
<li> </li>
<li>Covers</li>
<li> </li>
<li>Advertising</li>
<li> </li>
<li>Film</li>
</ul>
</div>`
and the current js.
<script type="text/javascript">
jQuery(document).ready(function(){
var mycontainer = jQuery('#isocontent');
mycontainer.isotope({
itemSelector: '.postContainer',
});
// filter items when filter link is clicked
jQuery('#options a').click(function(){
var selector = jQuery(this).attr('data-filter');
mycontainer.isotope({ filter: selector });
return false;
});
// set selected menu items
var $optionSets = $('.option-set'),
$optionLinks = $optionSets.find('a');
$optionLinks.click(function(){
var $this = $(this);
// don't proceed if already selected
if ( $this.hasClass('selected') ) {
return false;
}
var $optionSet = $this.parents('.option-set');
$optionSet.find('.selected').removeClass('selected');
$this.addClass('selected');
});
});
</script>
All help would be greatly appreciated.
Thank you!
Ok, seeing is believing :) easier to understand what you want. Basically, all you have to do is to hook up what I commented before on your Editorial, Covers, Advertising, Film links. Since you use Isotope with filtering, you have assigned click functions to your links already...
// stuff
<ul id="filters">
<li>Show all, home, whatever</li>
<li>Editorial</li>
<li>Covers</li>
<li>Advertising</li>
<li>Film</li>
</ul>
// more stuff
$('#filters a').click(function() {
var selector = $(this).attr('data-filter');
$container.isotope({
filter: selector
});
$('body,html').animate({ // always scrolls to the top when filter link is clicked
scrollTop: 0
}, 800);
return false;
});
// even more stuff