Trigger next and previous element in 'vue-owl-carousel' package Vue.js - javascript

I have problem with triggering next or previous item in vue-owl-carousel package in Vue with javascript.
Can anybody help?
Carousel code :
<carousel id="newGamesCarousel" :items="1" :dots="false" :nav="false" :margin="10" :key="refresh">
<div class="newGames-item" v-for="item in newProducts">
<div class="details">
<div class="labels flex-wrap">
<span class="mb-1" v-for="platform in item.platforms">{{platform.name}}</span>
<span class="mb-1" v-for="region in item.regions">ریجن {{region.name}}</span>
</div>
<h2 class="gameTitle">{{item.name}}</h2>
<div class="priceBox">
<router-link class="add-to-cart" :to="{path: '/game/'+item.id+'/'+stringToSlug(item.title)+''}">+</router-link>
<div class="price">
<div class="former" v-if="item.sale_percent !== false">
<span class="percent">%{{item.sale_percent}}</span>
<span class="total">{{item.price}}</span>
</div>
<div class="later">
{{item.regular_price}}
<span class="unit">تومان</span>
</div>
</div>
</div>
</div>
<figure class="image">
<img v-bind:src="item.thumbnail_url" v-bind:alt="item.name">
</figure>
</div>
</carousel>
And the next and previous buttons:
<div class="arrows">
<svg class="nextCarousel" id="newGamesNext" viewBox="0 0 24 24">
<use xlink:href="/src/assets/imgs/sprite.svg#arrow"></use>
</svg>
<svg class="prevCarousel" id="newGamesPrev" viewBox="0 0 24 24">
<use xlink:href="/src/assets/imgs/sprite.svg#arrow"></use>
</svg>
</div>

as per documentation described here : https://www.npmjs.com/package/vue-owl-carousel
Custom prev and next buttons using slot, the buttons will be hidden
while start and end in non-loop mode
<carousel>
<template slot="prev"><span class="prev">prev</span></template>
<template slot="next"><span class="next">next</span></template>
</carousel>
within the carousel tag after adding all your slides
you can add <template slot="{{prev/next}}">{{add your icon image here }}</template> and it should take care of the previous and next events on its own
<template slot="prev">
<svg class="nextCarousel" id="newGamesNext" viewBox="0 0 24 24"><use xlink:href="/src/assets/imgs/sprite.svg#arrow"></use></svg>
</template>
this is what I feel should solve your issue. If Im missing something feel free to add urls of documentations/ tutorials that you followed to get your code here. please let me know if the solution worked or not

<v-flex>
<span #click="$refs.prev.click()">
PREVIOUS
</span>
<span #click="$refs.next.click()">
NEXT
</span>
</v-flex>
<v-flex>
<carousel>
<template slot="prev"><span hidden ref="prev" class="prev">prev</span></template>
<template slot="next"><span hidden ref="next" class="next">next</span></template>
</carousel>
</v-flex>

Related

VueJS - Click event is not triggered as parent event prevaults

I am building a search input that fetchs data from my API and lists it in a dropdown list.
Here is the behavior I want my component to have:
If I start typing and my API founds data, it opens the dropdown menu and lists it.
If I click on one of the elements from the list, it is set as 'activeItem' and the dropdown list closes
Else, I can click out of the component (input and dropdown list) and the dropdown list closes
Else, no dropdown list appears and my input works like a regular text input
My issue has to do with Event Bubbling.
My list items (from API) have a #click input that set the clicked element as the 'activeItem'.
My input has both #focusin and #focusout events, that allow me to display or hide the dropdown list.
I can't click the elements in the dropdown list as the #focusout event from the input is being triggered first and closes the list.
import ...
export default {
components: {
...
},
props: {
...
},
data() {
return {
results: [],
activeItem: null,
isFocus: false,
}
},
watch: {
modelValue: _.debounce(function (newSearchText) {
... API Call
}, 350)
},
computed: {
computedLabel() {
return this.required ? this.label + '<span class="text-primary-600 font-bold ml-1">*</span>' : this.label;
},
value: {
get() {
return this.modelValue
},
set(value) {
this.$emit('update:modelValue', value)
}
}
},
methods: {
setActiveItem(item) {
this.activeItem = item;
this.$emit('selectItem', this.activeItem);
},
resetActiveItem() {
this.activeItem = null;
this.isFocus = false;
this.results = [];
this.$emit('selectItem', null);
},
},
emits: [
'selectItem',
'update:modelValue',
],
}
</script>
<template>
<div class="relative">
<label
v-if="label.length"
class="block text-tiny font-bold tracking-wide font-medium text-black/75 mb-1 uppercase"
v-html="computedLabel"
></label>
<div :class="widthCssClass">
<div class="relative" v-if="!activeItem">
<div class="flex items-center text-secondary-800">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-3.5 w-3.5 ml-4 absolute"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
<!-- The input that triggers the API call -->
<input
class="text-black py-2.5 pr-3.5 pl-10 text-black focus:ring-primary-800 focus:border-primary-800 block w-full rounded sm:text-sm border-gray-300"
placeholder="Search for anything..."
type="text"
#input="$emit('update:modelValue', $event.target.value)"
#focusin="isFocus = true"
#focusout="isFocus = false"
>
</div>
<!-- The Dropdown list -->
<Card
class="rounded-t-none shadow-2xl absolute w-full z-10 mt-1 overflow-y-auto max-h-48 px-0 py-0"
v-if="isFocus && results.length"
>
<div class="flow-root">
<ul role="list" class="divide-y divide-gray-200">
<!-- API results are displayed here -->
<li
v-for="(result, index) in results"
:key="index"
#click="setActiveItem(result)" <!-- The event I can't trigger -->
>
<div class="flex items-center space-x-4 cursor-pointer px-4 py-3">
<div class="flex-shrink-0">
<img
class="h-8 w-8 rounded-md ring-2 ring-lighter shadow-lg"
:src="result.image ?? this.$page.props.page.defaultImage.url"
:alt="result.title"
/>
</div>
<div class="min-w-0 flex-1">
<p
class="truncate text-sm font-medium text-black"
:class="{
'text-primary-900 font-bold': result.id === activeItem?.id
}"
>
{{ result.title }}
</p>
<p class="truncate text-sm text-black/75">
{{ result.description }}
</p>
</div>
<div v-if="result.action">
<Link
:href="result.action?.url"
class="inline-flex items-center rounded-full border border-gray-300 bg-white px-2.5 py-0.5 text-sm font-medium leading-5 text-black/75 shadow-sm hover:bg-primary-50"
target="_blank"
>
{{ result.action?.text }}
</Link>
</div>
</div>
</li>
</ul>
</div>
</Card>
</div>
<!-- Display the active element, can be ignored for this example -->
<div v-else>
<article class="bg-primary-50 border-2 border-primary-800 rounded-md">
<div class="flex items-center space-x-4 px-4 py-3">
<div class="flex-shrink-0">
<img
class="h-8 w-8 rounded-md ring-2 ring-lighter shadow-lg"
:src="activeItem.image ?? this.$page.props.page.defaultImage.url"
:alt="activeItem.title"
/>
</div>
<div class="min-w-0 flex-1">
<p class="truncate text-sm font-medium text-black font-bold">
{{ activeItem.title }}
</p>
<p class="truncate text-sm text-black/75 whitespace-pre-wrap">
{{ activeItem.description }}
</p>
</div>
<div class="flex">
<AppButton #click.stop="resetActiveItem();" #focusout.stop>
<svg
class="w-5 h-5 text-primary-800"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
></path>
</svg>
</AppButton>
</div>
</div>
</article>
</div>
</div>
</div>
</template>
Here is a look at the input:
With API results (can't click the elements):
When no data is found:
I tried:
handleFocusOut(e) {
console.log(e.relatedTarget, e.target, e.currentTarget)
// No matter where I click:
// e.relatedTarget = null
// e.target = <input id="search" class="...
// e.currentTarget = <input id="search" class="...
}
...
<input
id="search"
class="..."
placeholder="Search for anything..."
type="text"
#input="$emit('update:modelValue', $event.target.value)"
#focusin="isFocus = true"
#focusout="handleFocusOut($event)"
>
The solution:
relatedTarget will be null if the element you click on is not
focusable. by adding the tabindex attribute it should make the element
focusable and allow it to be set as relatedTarget. if you actually
happen to be clicking on some container or overlay element make sure
the element being clicked on has that tabindex="0" added to it so you
can maintain isFocus = true
Thanks to #yoduh for the solution
The root issue looks to be how the dropdown list is being removed from the DOM as soon as the input loses focus because of the v-if on it.
<Card
v-if="isFocus && results.length"
>
This is ok to have, but you'll need to work around it by coming up with a solution that keeps isFocus true whether the focus is on the input or the dropdown. I would suggest your input's #focusout to execute a method that only sets isFocus = false if the focus event's relatedTarget is not any of the dropdown items (can be determined via classname or other attribute). One roadblock to implementing this is that some elements aren't natively focusable, like <li> items, so they won't be set as the relatedTarget, but you can make them focusable by adding the tabindex attribute. Putting it all together should look something like this:
<input
type="text"
#input="$emit('update:modelValue', $event.target.value)"
#focusin="isFocus = true"
#focusout="loseFocus($event)"
/>
...
<li
v-for="(result, index) in results"
:key="index"
class="listResult"
tabindex="0"
#click="setActiveItem(result)"
>
loseFocus(event) {
if (event.relatedTarget?.className !== 'listResult') {
this.isFocus = false;
}
}
setActiveItem(item) {
this.activeItem = item;
this.isFocus = false;
this.$emit('selectItem', this.activeItem);
}

The JS code for my Tailwind Image Slider won't work :/

I am new to the whole coding topic. For my first "big" project I want to build a simple website with some functionality. I tried to implement an Image slider with Tailwind and JS. But the Code won't work. Thank you for all your help in advance <3screen
HTML and Tailwind:
<section>
<div>
<div class="relativ h-50 relative">
<ul id="slider">
<li class="relativ scale-50">
<img class="h-full w-full object-fill" src="./img/test.png" alt="" />
</li>
<li class="relativ hidden h-[50vh]">
<img class="h-full w-full object-fill" src="./img/logo1.png" alt="" />
</li>
<li class="relativ hidden h-[50vh]">
<img class="h-full w-full object-fill" src="./img/test.png" alt="" />
</li>
</ul>
<div class="absolute top-1/2 -translate-y-1/2 w-full px-5">
<div class="my-auto flex w-full justify-between ">
<button onclick="prev()" class="rounded-full bg-slate-500 bg-opacity-80 p-3 shadow-lg">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-6 w-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
</svg>
</button>
<button onclick="next()" class="rounded-full bg-slate-500 bg-opacity-80 p-3 shadow-lg">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-6 w-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
</svg>
</button>
</div>
</div>
</div>
</div>
</section>
JS:
// Image slider
currentSlideId = 1;
sliderElement = document.getElementById('slider');
totalSlides = sliderElement.childElementCount;
function next (){
if(totalSlides<currentSlideId){
currentSlideId++;
showSlide();
}
}
function prev(){
if(currentSlideId > 1){
currentSlideId--;
showSlide();
}
}
function showSlide(){
slides = getElementById('slider').getElementsByTagName('li');
for (let index = 0; index < totalSlides; i++){
const element = slide[index];
if(currentSlideId===index+1){
element.classList.remove('hidden')
}else{
element.classList.add('hidden')
}
}
}
I tried to edit my code but it won't work :/
First, welcome to stack overflow.
I think the problem is in the showSlide function inside the for loop, wherein the 'element' variable you wrote:
slide[index]
But I think it should be:
slides[index]
Because there is no variable in that name.
And also like #BestCoderBoy commended, it's always good to initialize a variable before using it, and it looks like you're using getElementByID without the document.

How to properly set img href path?

I am writing an update to my personal website where I remove duplicate html code. I am running into an error when I try to dynamically set the path to the href element.
Error: "ERROR TypeError: Cannot set property href of [object SVGImageElement] which has only a getter"
All other {{var}} instances work as expected
code that throws error:
<div class="row featurette" *ngFor="let row of json" >
<div class="col-md-7 {{row.textSpacing}}">
<h2 class="featurette-heading">{{row.title}}</h2>
<p class="lead">{{row.subTitle}}</p>
</div>
<div class="col-md-5 {{row.photoSpacing}}">
<svg class="bd-placeholder-img bd-placeholder-img-lg featurette-image img-fluid mx-auto" width="500" height="500" preserveAspectRatio="xMidYMid slice" focusable="false" role="img" >
<image href={{row.src}} height="100%" width="100%"/>
</svg>
</div>
</div>
working code:
<div class="row featurette" *ngFor="let row of json" >
<div class="col-md-7 {{row.textSpacing}}">
<h2 class="featurette-heading">{{row.title}}</h2>
<p class="lead">{{row.subTitle}}</p>
</div>
<div class="col-md-5 {{row.photoSpacing}}">
<svg class="bd-placeholder-img bd-placeholder-img-lg featurette-image img-fluid mx-auto" width="500" height="500" preserveAspectRatio="xMidYMid slice" focusable="false" role="img" >
<image href="/assets/images/hiking.JPG" height="100%" width="100%"/>
</svg>
</div>
</div>
Data Structure:
json = [
{
src: "/assets/images/hiking.JPG",
textSpacing:"",
photoSpacing:"",
title:"Hiking",
subTitle:"I love exploring with friends. The ability to be in untouched protected nature is something I value deeply. Most recent trip: Yosemite and Sequoia national parks. Hiker Pro Tip: Drop a GPS pin on your phone at the trailhead"
},
{
src: "/assets/images/Skiing.png",
textSpacing:"order-md-2",
photoSpacing:"order-md-1",
title:"Skiing",
subTitle:"I recently picked up skiing as an adult. This past winter I was able to go to Colorado to Ski in the mountains. Amazing!"
}
]
I believe you would need to do the [attr.href] for this to work. Example shown below.
<image [attr.href]="row.src" height="100%" width="100%"/>
or
<image attr.href={{row.src}} height="100%" width="100%"/>
You need quotes around your value {{row.src}}
<image href="{{row.src}}" height="100%" width="100%"/>

Keep all style of page inside page block element

I have this code :
<div class="page-payment">
<div class="payment-methods" v-if="!pending">
<sepa-modal
ref="sepaModal"
/>
</div>
</div>
SepaModal.vue :
<b-modal
id="sepaModal"
centered
top
no-fade
size="md"
ref="modal"
hide-footer
#show="showPopup"
#hidden="closePopup"
>
<template #modal-header-close>
<icon width="20" height="20" class="d-none d-md-block" type="times"/>
<icon width="10" height="18" class="d-md-none" type="arrow-left"/>
</template>
<template #modal-title>
</template>
<div>
<div class="content-modal content-modal-sepa">
<div class="modal-header"></div>
..........
</div>
</div>
The .css :
.page-payment {
.payment-methods {
.content-modal {
padding: 20px !important
}
}
}
The style is not getting into account. But I want to keep all styles inside: .page-payment{}. How can I solve it?

neon-animated-pages with embedded dom-repeat element

We are building a survey mechanism where we can have the user create their own set of questions, the type, etc. The users can show up a single element at a time. Or a group of questions. I use the neon-animated-pages to go from one singular question to another.
-- index.html --
<iron-pages attr-for-selected="data-route" selected="{{route}}">
<section data-route="home">
<test-survey surveyid="99999999-9999-9999-9999-999999999999" submissionid='00000000-0000-0000-0000-000000000000'}' ></test-survey>
</section>
<section data-route="users">
<paper-material elevation="1">
</paper-material>
</section>
<section data-route="user-info">
<paper-material elevation="1">
</paper-material>
</section>
<section data-route="contact">
<paper-material elevation="1">
</paper-material>
</section>
</iron-pages>
--test-survey.html--
<div class="vertical layout">
<div class="flex">
<neon-animated-pages id="views" class="flex" selected="0" entry-animation="slide-from-right-animation" exit-animation="slide-left-animation">
<test-template items="{{survey.Questions}}" id="surveyquestions">
</test-template>
</neon-animated-pages>
<paper-toast
id="toast"
text="Saved successfully.">
</paper-toast>
</div>
</div>
Since needing to be able to group questions together, we moved the following code to another file, stand alone so it can be called from a place where single questions are asked. Or from a place where it will take a list of questions as a group and show them within one section.
--test-template.html--
<template>
<template is="dom-repeat" id="surveyquestions" items="{{items}}" sort="_sort">
<template is="dom-if" if="{{isFormat(item.Type, 'Single-Select')}}" >
<question-singleselect question="{{item}}"></question-singleselect>
</template>
<template is="dom-if" if="{{isFormat(item.Type,'Open-Ended')}}">
<question-openended question="{{item}}"></question-openended>
</template>
<template is="dom-if" if="[[isFormat(item.Type,'Multi-Select')]]">
<question-multiselect question="{{item}}"></question-multiselect>
</template>
<template is="dom-if" if="[[isFormat(item.Type,'Section')]]">
<question-section question="{{item}}"></question-section>
</template>
<template is="dom-if" if="{{isFormat(item.Type,'Numerical')}}">
<question-numerical question="{{item}}"></question-numerical>
</template>
</template>
</template>
--test-chrome.html--
<template>
<paper-card heading="{{question.Title}}" id="paper-card-{{question.Id}}">
<div class="card-content {{question.Type}}">
<div class="questionanswers">
<content select=".questionanswers"></content>
</div>
</div>
<div class="card-actions">
<paper-button class="raised primary" on-tap="prevAction" id="prevButton_{{question.Id}}" hidden$="{{_hidePrev(question.Type)}}">Previous</paper-button>
<paper-button class="raised primary" on-tap="nextAction" id="nextButton_{{question.Id}}" hidden$="{{_hideNext(question.Type)}}">Next</paper-button>
<paper-button class="raised primary" on-tap="saveAction" id="saveButton_{{question.Id}}" hidden$="{{_hideSave(question.Type)}}">Submit</paper-button>
</div>
</paper-card>
</template>
Once I put the list of question-types into a separate form, it stopped working. It listed all the questions on one page, instead of navigating from one question to the next. It works if the section of test-template.html is back in the test-survey.html

Categories

Resources