How to select all of the elements with class "backbtn" that is in another function? - back-button

I am trying to select all the elements with the class "backbtn", but its not that easy since all the elements with that class is currently not in the DOM when page is freshly loaded but only in the DOM when a certain button is clicked.
I tried fixing it by putting it in a setInterval like this:
document.querySelector(".backbtn").forEach(el => el.addEventListener("click", () => {
if(document.querySelector(".backbtn")!=null){
goBack();
} return null;
}))
}, 10)```
but it dosent work.

Related

k6: How to create a Selection from an Element

Using Selection.each(fn) (see the k6 docs), the callback is passed an index and an Element. Element has a different API than Selection, and within the callback I’d like to use the Selection API on the passed Element so that I can operate on each Selection individually.
In jQuery, I’d often do this:
$('li').each(function (index, element) {
let container = $(element).closest('div.listContainer');
// now do something with the `container`
});
I’ve tried inside the callback to do things like $(element) or Selection(element) but it errors saying those are undefined. (Kind of stabbing in the dark, since I don’t see in the docs how to do this.)
My code looks like:
mySelection.each((index, element) => {
// here, I'd like to do element.closest('.someAncestorSelector') if element could be 'wrapped'
})
Is there a way in the jQuery-like Selection API in k6 to do this?
From the k6 docs on Selection.closest:
For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. [emphasis mine]
Which means that each is unnecessary and will be performed automatically (returning a new Selection instance with the closest elements).
const closestSelection = mySelection.closest('.someAncestorSelector');
closestSelection.each((index, closestElement) => {
// now, do something with closestElement.
});
or as a single chain of expressions:
mySelection.closest('.someAncestorSelector')
.each((index, closestElement) => {
// now, do something with closestElement.
});
Btw, even jQuery implicitly handles collections, so your jQuery code could be changed to:
const containers = $('li').closest('div.listContainer');
containers.each(function (index, container) {
container = $(container);
// now do something with the `container`
});

react - add a classname to a specific element by clicking the button

I am new to reactjs. A sign in and sign up component is created. When clicking the button, a classname is supposed to be added to the specific element, in my case, signWrapper. I've tried few ways but it doesn't work. How do I add a classname to a specific element by clicking the button?
My code is on the codesandbox. Any suggestions are highly appreciated.
https://codesandbox.io/s/stoic-hertz-pmk23?file=/src/SignInAndSignUp.js:0-2298
you used your onClick function in a wrong way . you have to invoke this .
instead of this
onClick = { () => this.handleClick}
you have to do this
onClick = { () => this.handleClick()}
and handle your onClick like this
handleClick = () => {
this.setState({ active: !this.state.active }); // to toggle the state
};
here is the working example https://codesandbox.io/s/delicate-star-ghp7h?file=/src/SignInAndSignUp.js:283-360
Invoke your onClick function like so:
onClick={this.handleClick}
handleClick = () => {
// I added ...this.state so it doesn't affect any other state variables you may add
this.setState({ ...this.state, active: !this.state.active });
};
Also, check out the library clsx. It's very helpful when you have multiple classes needing to be activated or unactivated based on conditionals. This would look something more like the following:
className={clsx('signWrapper', { 'right-panel-active': active })}

VueJs child component props not updating instantly

I have a parent/child component setup where the parent is loading data from the server and passing it down to children via props. In the child I would like to instantiate a jQuery calendar with some of the data it receives from the parent.
In order to wait for the data before setting up the calendar, I broadcast an event in the parent that I have an event listener setup for in the child.
The listener is being fired in the child but if I this.$log('theProp'), it's undefined. However, if I inspect the components with the VueJs devtools, the parent/child relationship is there and the child has received the prop in the meantime.
The prop is defined on the child as a dynamic prop :the-prop="theProp". Since the child does receive the prop in the end, I'm assuming my setup is correct but there seems to be some sort of delay. The parent sets the props in the return function of the ajax call and again: it's working, just with a slight delay it seems.
I also tried registering a watch listener on the prop in the child so I could setup the calendar then and be sure that the prop is there. However, the watch listener fires, but this.$log('theProp') is still undefined.
If I pass the data along with the the broadcast call, like this.$broadcast('dataLoaded', theData) the child receives it just fine. But it seems wrong to do it that way as I'm basically building my own prop handler.
I'm not posting any code because the components are rather large and the VueJs devtools are telling me the parent/child situation is working.
Am I missing some information? Is there a slight delay between setting a value in the parent and the child receiving it? What would be the proper way to wait for parent data in the child?
Normally, when you're just rendering the data out into the template, the timing doesn't matter so much since the data is bound to the template. But in this case, I really need the data to be there to setup the calendar or it will be wrong.
Thanks.
edit 1: here's a jsfiddle: https://jsfiddle.net/dr3djo0u/1/
It seems to confirm that the data is not available immediately after the broadcast. However, the watcher does work, though I could almost swear that sometimes this.$log('someData') returned undefined when I setup that testcase.
But I guess my problem might be somewhere else, I'll have a look tonight, don't have the project with me right now.
edit 2: did some more tests. My problem was that a) event listeners do not seem to receive the data instantly and b) I was also trying to init the calendar in the route.data callback if someData was already around (e.g. when coming from parent), but that route callback is called before the component is ready, so it wasn't working there either.
My solution is now this:
// works when the child route is loaded directly and parent finishes loading someData
watch: {
someData() {
this.initCalendar();
}
},
// works when navigating from parent (data already loaded)
ready() {
if (this.someData && this.someData.length) {
this.initCalendar()
}
}
As far as I know, you should not need events to pass data from parent to child.
All you need is, in the child component: props: ['theProp']
And when using the child component in the parent: <child :theProp="someData"></child>
Now, wherever in the parent you change someData, the child component will react accordingly.
You don't need events, you don't need "watch", you don't need "ready".
For example: after an AJAX call, in the parent's "ready", you load some data:
// at the parent component
data: function () {
return {
someData: {}
}
},
ready: function () {
var vm = this;
$.get(url, function(response) {
vm.someData = response;
});
}
Now, you do not need anything else to pass the data to the child. It is already in the child as theProp!
What you really need to do is to have, in the child, something which reacts to data changes on its own theProp property.
Either in the interface:
<div v-if="theProp.id > 0">
Loaded!
</div>
Or in JavaScript code:
// at the child component
computed: {
// using a computed property based on theProp's value
awesomeDate: function() {
if (!this.theProp || (this.theProp.length === 0)) {
return false;
}
if (!this.initialized) {
this.initCalendar();
}
return this.theProp.someThing;
}
}
Update 1
You can also, in the parent, render the child conditionally:
<child v-if="dataLoaded" :theProp="someData"></child>
Only set dataLoaded to true when the data is available.
Update 2
Or maybe your issue is related to a change detection caveat
Maybe you're creating a new property in an object...
vm.someObject.someProperty = someValue
...when you should do...
vm.$set('someObject.someProperty', someValue)
...among other "caveats".
Update 3
In VueJS 2 you are not restricted to templates. You can use a render function and code the most complex rendering logic you want.
Update 4 (regarding OP's edit 2)
Maybe you can drop ready and use immediate option, so your initialization is in a single place:
watch: {
someData: {
handler: function (someData) {
// check someData and eventually call
this.initCalendar();
},
immediate: true
}
}
It's because tricky behavior in Vue Parent and Child lifecycle hooks.
Usually parent component fire created() hook and then mount() hook, but when there are child components it's not exactly that way: Parent fires created() and then his childs fire created(), then mount() and only after child's mount() hooks are loaded, parent loads his mount() as explained here. And that's why the prop in child component isn't loaded.
Use mounted() hook instead created()
like that https://jsfiddle.net/stanimirsp5/xnwcvL59/1/
Vue 3
Ok so I've spent like 1.5h trying to find out how to pass prop from parent to child:
Child
<!-- Template -->
<template>
<input type="hidden" name="_csrf_token" :value="csrfToken">
<span>
{{ csrfToken }}
</span>
</template>
<!-- Script -->
<script>
export default {
props: [
"csrfToken"
]
}
</script>
Parent
<!-- Template -->
<template>
<form #submit.prevent="submitTestMailForm" v-bind:action="formActionUrl" ref="form" method="POST">
...
<CsrfTokenInputComponent :csrf-token="csrfToken"/>
...
</form>
</template>
<!-- Script -->
<script>
...
export default {
data(){
return {
...
csrfToken : "",
}
},
methods: {
/**
* #description will handle submission of the form
*/
submitTestMailForm(){
let csrfRequestPromise = this.getCsrfToken();
let ajaxFormData = {
receiver : this.emailInput,
messageTitle : this.titleInput,
messageBody : this.bodyTextArea,
_csrf_token : this.csrfToken,
};
csrfRequestPromise.then( (response) => {
let csrfTokenResponseDto = CsrfTokenResponseDto.fromAxiosResponse(response);
this.csrfToken = csrfTokenResponseDto.csrToken;
this.axios({
method : "POST",
url : SymfonyRoutes.SEND_TEST_MAIL,
data : ajaxFormData,
}).then( (response) => {
// handle with some popover
})
});
},
/**
* #description will return the csrf token which is required upon submitting the form (Internal Symfony Validation Logic)
*/
getCsrfToken(){
...
return promise;
}
},
components: {
CsrfTokenInputComponent
}
}
</script>
Long story short
This is how You need to pass down the prop to child
<CsrfTokenInputComponent :csrf-token="csrfToken"/>
NOT like this
<CsrfTokenInputComponent csrf-token="csrfToken"/>
Even if my IDE keep me telling me yeap i can navigate with that prop to child - vue could not bind it.
solution (testing ok)
In child component just using the props data, no need to re-assignment props's values to data, it will be cause update bug!
vue child component props update bug & solution
https://forum.vuejs.org/t/child-component-is-not-updated-when-parent-component-model-changes/18283?u=xgqfrms
The problem is not how to pass data with props, but rather how to do two things at almost the same time.
I have an user account component that can edit users (with an user id) and add users (without id).
A child component shows checkboxes for user<->company assignments, and needs the user id to prepare API calls when the user account is saved.
It is important that the child component shows before saving the user account, so that things can be selected before the user is saved and gets an id.
So it has no user id at first: the id is passed to the child component as 'null'.
It updates when the user is stored and gets an id.
But at this point, it takes a very short time for the child to get the new id into its model.
If you call a function in the child component that relies on data that was just changing, it might happen that the function executes before the data is updated.
For cases like this, nextTick() is your friend.
import { nextTick } from 'vue';
...
saveAccount() {
axios.post(URL, this.userModel).then((result)) {
// our model gets an id when persisted
this.userModel.id=result.data.id;
nextTick( () => {
this.$refs.childComponent.doSomething();
});
}
}

Knockout 2 way foreach binding DOM changes update Model

If I have a list on a page, and it is using knockout's foreach binding to display list items, then something else updates the DOM to add an extra list item. If there any way I can get knockout to detect that DOM change and update its model to add the new item to the observableArray?
Here is a fiddle which shows the problem...
http://jsfiddle.net/BGdWN/1/
function MyViewModel() {
this.items = ko.observableArray([
{ name: 'Alpha' }, { name: 'Beta' }, { name: 'Gamma' }, { name: 'Delta' }
]);
this.simpleShuffle = function() {
this.items.sort(function() {
return Math.random() - 0.5; // Random order
});
};
this.simpleAdd = function() {
$("#top").append("<li>New item</li>");
}
}
ko.applyBindings(new MyViewModel());
It has 2 lists bound to the same observableArray, click the addItem button and you can see that the DOM is updated to include the new list item in the top list, but I would like the second list to be updated too, all via the model.
It seems that knockout ignores DOM elements that it didnt render, you can see this by clicking the shuffle button, it leaves the new items there. I would have expected it to remove them and do a full re-render.
Please don't answer with "Just add the item to the observableArray"
Take a look at the first link and the second link Interface MutationEvent
See Fiddle
$('#top').bind('DOMNodeInserted DOMNodeRemoved', function () {
alert('Changed');
});
I hope it helps.

Adding filtering to jquery-isotope within Wordpress theme

I'm using the Vitrux theme in Wordpress that uses Isotope jQuery plugin to display a work porfolio. Isotope allows categories to be used to sort the items, but within the theme it's only possible to sort by one category at a time (e.g. 'Year' or 'Type', not 'Year' and 'Type'.
You can see a mock-up here: http://snaprockandpop.samcampsall.co.uk/shoots/
The jQuery attached to each category item, that sorts the posts, is as follows:
function (){
var selector = $(this).attr('data-filter');
$container_isotope.isotope({ filter: selector });
var $parent = $(this).parents(".filter_list");
$parent.find(".active").removeClass('active');
$(".filter_list").not($parent).find("li").removeClass('active').first().addClass("active");
$(this).parent().addClass("active");
return false;
}
I can see from the Isotope site that it's possible to use multiple filters, and I've found the authors notes on this here: http://jsfiddle.net/desandro/pJ6W8/31/
EDIT:
Editing the theme files has allowed me to assign appropriate classes and properties to the filter lists (you can see these in the page source) and I'm targeting them through an edited version of the jsfiddle to reflect the classes and id's in the theme styling:
$( function() {
var $container = $('#portfolio_container');
$container.isotope({
animationOptions: { duration: 300, easing: 'linear', queue: false },
getSortData : {
year : function ( $elem ) { return parseFloat( $elem.find('._year').text() ); },
live-shows : function ( $elem ) { return parseFloat( $elem.find('._live-shows').text() ); }
}
});
var filters = {};
$('.ql_filter a').click(function(){
var $this = $(this);
if ( $this.hasClass('selected') ) {
return;
}
var $optionSet = $this.parents('.filter_list');
$optionSet.find('.active').removeClass('active');
$this.addClass('active');
var group = $optionSet.attr('data-filter-group');
filters[ group ] = $this.attr('data-filter');
var isoFilters = [];
for ( var prop in filters ) {
isoFilters.push( filters[ prop ] )
}
var selector = isoFilters.join('');
$container.isotope({ filter: selector });
return false;
});
});
Two (fairly major) things:
1) I'm not 100% that I've edited this correctly. Despite Rich's excellent comments I'm still out of my depth. I'm particularly not clear on how to set-up the 'getSortData' section - I think it's right but any input would be great.
2) I'm not sure that this JavaScript is being initiated. At the moment I've placed it immediately before the closing head tag but a check on the page suggests that the original script outlined above is the one running on the filter items.
Any pointers at this stage would be fantastic!
I see what you mean. You are looking for the intersection of both filters and not the mutually exclusive filter values.
Short answer: Contact the theme vendor and see if they can make the intersection filters for you.
Longer assistance (not an answer):
Your ultimate goal is to get the Vitrux theme working the way you want.
Your first goal is to understand what the jsfiddle code is doing.
I can handle your first goal by explicating the code.
// hook into the JQuery Document Load event and run an anonymous function
$( function() {
// Create a variable called container
// make container refer to the element with ID Container
var $container = $('#container');
// initialize isotope
// Call the isotope method on the container element
$container.isotope({
// options...
//distracting options
animationOptions: { duration: 300, easing: 'linear', queue: false },
getSortData : {
price : function ( $elem ) { return parseFloat( $elem.find('.price').text() ); },
size : function ( $elem ) { return parseFloat( $elem.find('.size').text() ); }
}
});
// sorting button
//for the anchor tag that has a class of 'pricelow', wire up an anonymous function to the click event
$('a.pricelow').click(function(){
//Rerun the isotope method when it is clicked, pass an array of options as a parameter
$('#container').isotope({ sortBy : 'price',sortAscending : true });
//return false for the anonymous function. Not 100% sure why this is necessary but it has bitten me before
return false;
});
//removed the rest of the click methods, because it does the same thing with different params
//Here is what you are interested in understanding
//Create an empty filters object
var filters = {};
// filter buttons
//When an anchor tag with class filters is clicked, run our anonymous function
$('.filters a').click(function(){
//Create a variable that is the action anchor element
var $this = $(this);
// don't proceed if already selected by checking if a class of "selected" has already been applied to the anchor
if ( $this.hasClass('selected') ) {
return;
}
//Create an optionSet Variable, point it to the anchor's parent's class of "option-set"
var $optionSet = $this.parents('.option-set');
// change selected class
//Inside the optionSet, find elements that match the "selected" class and then remove the "selected class"
$optionSet.find('.selected').removeClass('selected');
// set this (the anchor element) class to "selected"
$this.addClass('selected');
// store filter value in object
// create a variable called 'group' that points to the optionsSet variable and grab the data-filter-group expando attribute
var group = $optionSet.attr('data-filter-group');
//Append to the filters object at the top of this section and set the data-filter-group value to the anchor tag's data-filter value
filters[ group ] = $this.attr('data-filter');
//create an isoFilters array variable
var isoFilters = [];
//Loop through each one of the items in filters (give the item an alias variable called 'prop'
for ( var prop in filters ) {
//push the prop into the isoFilters array (the opposite is pop)
isoFilters.push( filters[ prop ] )
//keep looping until there are no more items in the object
}
//create a variable called selector and turn the array into a string by joining all of the arrays together
var selector = isoFilters.join('');
//Like always, call the 'isotope' method of the 'container' element and pass our newly concatenated 'selector' string as the 'filter' option.
$container.isotope({ filter: selector });
//return false for some reason (maybe someone can expand on that)
return false;
});
});
Next is your ultimate goal which is modifying the Vitrux theme to handle intersection filters.
This gets a little tricky because
You have automatically generated tags from PHP to create the category links and the Year filter. So, there will be definitely some PHP code changes.
You must convert the jsfiddle code to handle your PHP changes
Try it using jQuery noconflict. In effect, replace any "$" with "jQuery" and see if it works.
Wordpress doesn't play well with the dollar sign.

Resources