Getting the current position of the slide when you swipe on VueJS? - vue.js

So basically, i'm trying to get the position of the slide and then update the html by adding a class to that slide. But I can't figure out how to get the current position everytime I swipe, how to update the swipe_active data.
This is the vue js file.
mounted(){
let element = document.getElementById('mySwipe');
if (window.innerWidth< 550){
window.mySwipe = Swipe (element, {
startSlide: 1,
auto: 0,
autoRestart: true,
continuous: true,
disableScroll: true,
stopPropagation: true,
callback: function(index, element) {},
transitionEnd: function(index, element) {}
});
}
this.swipe_active = window.mySwipe.getPos();
}
This is the html
<div :class="{black_swipe : swipe_active === 0 }"></div>
<div :class="{black_swipe : swipe_active === 1 }"></div>

mounted hook is called only once i.e when the component is finished mounting the DOM.
There is a callback property your have available in the config option you pass while creating a new Swipe instance. This property takes a function that will be called after every slide change
you can use this to update the swipe_active data.
mounted(){
let element = document.getElementById('mySwipe');
if (window.innerWidth< 550){
window.mySwipe = new Swipe (element, {
startSlide: 1,
auto: 0,
autoRestart: true,
continuous: true,
disableScroll: true,
stopPropagation: true,
callback: this.swipeCallback,
transitionEnd: function(index, element) {}
});
}
this.swipe_active = window.mySwipe.getPos();
},
methods: {
swipeCallback(index, element){
this.swipe_active = window.mySwipe.getPos();
}
}

Related

Codemirror does not refresh the contents of the textarea until its clicked or if I use the JSON.parse on the contents while setting

I am developing a web application using Vuejs/Nuxtjs within that I have some textarea which is controlled by CodeMirror for beautification purposes. The problem I am facing is that when the content of the CodeMirror changes then it is not reflected on the CodeMirror textarea unless I click on it or if I use the JSON.parse while setting the value in Watch. If I click on it then it reflects the changes and everything is correctly working.
Following is the textarea which is governed by CodeMirror:
<textarea
ref="input"
:value="$store.state.modules.MyModules.input"
class="form-control"
placeholder="Input"
spellcheck="false"
data-gramm="false"
/>
Following is the code sample where I am loading the contents to CodeMirror if the values changes using the Vuejs Watch function:
data () {
return {
inputEditor: null
}
},
watch: {
'$store.state.modules.MyModules.input' (value) {
if (value !== this.inputEditor.getValue()) {
this.inputEditor.setValue(value)
}
}
},
mounted () {
this.inputEditor = CodeMirror.fromTextArea(this.$refs.testInput, {
mode: "applicaton/ld+json",
beautify: { initialBeautify: true, autoBeautify: true },
lineNumbers: true,
indentWithTabs: true,
autofocus: true,
tabSize: 2,
gutters: ["CodeMirror-lint-markers"],
autoCloseBrackets: true,
autoCloseTags: true,
styleActiveLine: true,
styleActiveSelected: true,
autoRefresh: true,
});
// On change of input call the function
this.inputEditor.on("change", this.createTestData);
// Set the height for the input CodeMirror
this.inputEditor.setSize(null, "75vh");
// Add the border for all the CodeMirror textarea
for (const s of document.getElementsByClassName("CodeMirror")) {
s.style.border = "1px solid black";
}
}
I found issues similar to this and tried the following things but still no luck:
Trying to refresh the contents within the watch method:
watch: {
'$store.state.modules.MyModules.input' (value) {
const vm = this
if (value !== this.inputEditor.getValue()) {
this.inputEditor.setValue(value)
setTimeout(function () {
vm.inputEditor.refresh()
}, 1)
}
}
},
Trying to use the autorefresh within my CodeMirror but that also did not work.
What worked for me is that when setting the value I need to use the JSON.parse within the watch method. If I do that then It's working correctly but I do not want to do that:
watch: {
'$store.state.modules.MyModules.input' (value) {
const vm = this
if (value !== this.inputEditor.getValue()) {
this.inputEditor.setValue(JSON.parse(value))
}
}
},
Can someone please inform me why the CodeMirror data will not be updated if I do not do JSON.parse?
Chain this to the master codemirror object, make sure nothing else is chained:
.on('change', editor => {
globalContent = editor.getValue();
});;
Providing the answer as it can be helpful to someone else in the future:
Actually the vm.inputEditor.refresh() will work only problem was that I was using it with setTimeout 0.001s which is way to quick for to refresh.
After trying a lot I found my stupid mistake. I tried to change it to 1000 or 500 and it works now.
Following is the change:
setTimeout(function () {
vm.inputEditor.refresh()
}, 1000)

Update a data value from a method called in mounted

I have this code and the goal from it is to update a data sticky to true if the scroll position is > than 0
export default {
components: {
},
data() {
return {
menuVisible: false,
sticky: false,
}
},
mounted() {
this.checkScroll()
},
methods: {
checkScroll() {
document.querySelector('body').onscroll = function() {
console.log(window.pageYOffset > 0)
this.sticky = window.pageYOffset > 0
}
},
},
}
the problem is that even that i see the true console logged, the data is allways false ( as the initial value )
Any idea why is not updating it?
That's because of the callback you're passing into your scroll listener. In your callback this is not the context of the vue component. I think its the body actually. You'll need to use an arrow function or pass the vue instance into the callback as an argument. Arrow function is easiest. An arrow function retains the context where it was defined rather than inheriting the context of the object that calls it. Here is a good post/answer about the difference between normal and arrow functions.
document.querySelector('body').onscroll = () => {
console.log(window.pageYOffset > 0)
this.sticky = window.pageYOffset > 0
}

Vuejs2 issue passing data changes between children

Another issue with a project I am working on.
I have the following vuejs2 parent-child structure
Parent app
child product-list
product
product-image
colour-select
Within the product template I initiate the sibling components
The colourSelect component takes a comma delimited string and turns it into a drop down list. Whenever the selected option changes it emits the colour back to the product component which has a data variable "colour"
This appears to work fine.
The product-image component takes the product colour as a prop.
Whenever the colour changes I want the product-image component to detect it and trigger it to go get the relevant image. But its not detecting the change in colour.
Vue.component('product', {
props: ['productID', 'images', 'product'],
data: function () {
return {
colour: 'Navy',
}
},
computed: {
returnColour: function (colour) {
// this.colour = colour
//return colour
}
},
template: '<transition name="list"><li class="moving-item" id="productID">' +
'<product-image :productID="productID" :images="getImage(product.productID)" :colour="colour"></product-image>' +
'<colourSelect :colours="product.colour" :productID="product.productID" v-on:set-colour="setColour(colour)"></colourSelect>' +
'</li></transition>',
methods: {
getImage: function (listItemId) {
var images = this.images.filter(function (item) {
return returnCleanedData(item.Products_x003a_ID) === listItemId
})
},
setColour: function (colour) {
console.log('in main colour emit')
this.colour = colour
console.log(this.colour)
}
}
});
Vue.component('colourSelect', {
props: ['productID', 'colours', 'set-colour'],
template: '<select v-bind:id="getID()" class="form-control input-xs" :disabled=" isActive" v-bind:class="{disabledSelect: isActive}" v-on:click="setColour(productID)">' +
'<colourOption v-for="colourItem in colourArray">{{ colourItem.colour }}</colourOption>' +
'</select>',
data: function() {
return {
isActive: false
}
},
computed: {
colourArray: function () {
//splits data and applies it to the select
}
},
methods: {
getID: function () {
return 'colourSelect' + this.productID;
},
**setColour: function (productID) {**
//yeah used jquery here
var colour = $('#colourSelect' + productID).val()
this.$emit('set-colour', colour)
}
}
});
Vue.component('product-image', {
props: ['productID', 'images', 'colour'],
template: '<p><slot></slot><img :src="getImage(productID, images, colourSelected)" class="productImagePosition img-responsive img-rounded"></img></p>',
data: function () {
return {
isActive: false,
selectedColour: this.colour
}
},
computed: {
colourSelected: function () {
console.log('colour change detected')
return this.colour
}
},
methods: {
getID: function (test) {
return 'colourSelect' + this.productID;
},
getImage: function (listItemId, images, colour) {
console.log('selected colour')
console.log(colour)
//filter images to the specific colour and return link
},
}
});
The issue appears to be related to this line in the product template
v-on:set-colour="setColour(colour)"
When the child component emits the set-colour data back, the product is correctly running this method. But the product-image doesn't detect the change to its prop.
If i change the line to v-on:set-colour="setColour()" it will actually detect the change in the product-image but will error due to no data being passed.
Within the product-image component I have tried referencing a computed value (colourSelected) instead of the prop within the template which has no effect.
Any ideas?
Thanks
On product-image add a watcher to the colour prop:
watch: {
colour(value) {
// make changes here
},
},

Hide Pager if bxslider has only 1 slide

I'm trying to add a class "disabled" to the pager if the slider has only 1 slide showing, and nothing to actually slide.
I'm sliding a div, not a list.
It's just a basic div:
<div class="bxslider2">
<div class="wrap">
...
</div>
</div>
Here is the jquery for the slider:
$('.bxslider2').bxSlider({
mode: 'horizontal',
speed: '180',
pagerType:'full',
pager:'true',
captions: false
});
I would like to not show the pager if there is only 1 slide showing.
Thanks for any help!
Justin
I faced the same trouble and here is my solution: we should count how many child elements we have under .bxslider2 block
$(".bxslider2>.wrap").length
and if there is only one, then set option to 'false', otherwise to 'true'.
$('.bxslider2').bxSlider({
mode: 'horizontal',
speed: '180',
pagerType:'full',
pager: ($(".bxslider2>.wrap").length > 1) ? true: false,
captions: false
});
Hope it will helps.
I use css to achieve this.
.bx-pager-item:first-of-type:last-of-type {
display: none
}
Here is a solution if you have more than one bxslider on the page.
$('.bxslider').each(function() {
var options = {
mode: 'fade',
};
if ($(this).find('li').length === 1) {
options.pager = false;
}
$(this).bxSlider(options);
});
Goes through each slider and finds if it has only one li. If so, add pager: false to the object passed to bxSlider.
a nice way to solve this thing is to reload the object like that
and change the controls per number of the items :
var slideQty = $('.bxslider').bxSlider({
minSlides: 1,
maxSlides: 3,
slideWidth: 110,
slideMargin: 0,
adaptiveHeight: true,
pager: false,
moveSlides: 1,
onSlideAfter: function ($slideElement, oldIndex, newIndex) { NextSlide(oldIndex, newIndex); }
});
var count = slideQty.getSlideCount();
if (count < 7) {
slideQty.reloadSlider({
controls : false,
minSlides: 1,
maxSlides: 3,
slideWidth: 110,
slideMargin: 0,
adaptiveHeight: true,
pager: false,
moveSlides: 1,
onSlideAfter: function ($slideElement, oldIndex, newIndex) { NextSlide(oldIndex, newIndex); }
});
}
return false;
Try this it works for me!!
var slider = $('#slider').bxSlider();
$('.bx-next, .bx-prev, .bx-pager a').click(function(){
// time to wait (in ms)
var wait = 1000;
setTimeout(function(){
slider.startAuto();
}, wait);
});

Constrain position of Dojo FloatingPane

I have a dojox.layout.FloatingPane (as a custom dijit) which can be positioned anywhere within its enclosing div. My problem is that the user can potentially drag the FloatingPane completely outside of its container and be unable to retrieve it. Is there any easy way to force the FloatingPane to remain entirely visible at all times?
Here's my code:
dojo.provide("ne.trim.dijits.SearchDialog");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dojox.layout.FloatingPane");
dojo.declare("ne.trim.dijits.SearchDialog", [dijit._Widget, dijit._Templated], {
templateString: dojo.cache("ne.trim.dijits", "templates/SearchDialog.html"),
initialised:false,
floatingPane: null,
postCreate: function() {
this.init();
},
init: function() {
console.debug("SearchDialog.init()", "start");
if ( this.initialised === false ) {
this.createSearchDialog();
}
//ne.trim.AppGlobals.searchDialog = this;
console.debug("SearchDialog.init()", "end");
},
createSearchDialog: function() {
var node = dojo.byId('searchbox');
floatingPane = new dojox.layout.FloatingPane({
title: "A floating pane",
resizable: true, dockable: true, constrainToContainer: true,
style: "position:absolute;top:100;right:100;width:400px;height:300px;z-index:100",
}, node );
this.initialised=true;
floatingPane.startup();
}
});
First of all, see the working example at jsFiddle: http://jsfiddle.net/phusick/3vTXW/
And now some explanation;) The DnD functionality of FloatingPane is achieved via dojo.dnd.Moveable class instantialized in pane's postCreate method. To constrain the movement of the FloatingPane you should use one of these moveables instead:
dojo.dnd.parentConstainedMoveable - to constrain by a DOM node
dojo.dnd.boxConstrainedMoveable - to constrain by co-ordinates: {l: 10, t: 10, w: 100, h: 100}
dojo.dnd.constrainedMoveable - to constrain by co-ordinates calculated in a provided function
For more details see aforementioned jsFiddle.
According to documentation you should call destroy() on Moveable instance to remove it, but as FloatingPane's original Moveable is not assigned to any object property, I do not destroy it, I just instantiate one of those three moveables on the same DOM node in a subclass:
var ConstrainedFloatingPane = dojo.declare(dojox.layout.FloatingPane, {
postCreate: function() {
this.inherited(arguments);
this.moveable = new dojo.dnd.move.constrainedMoveable(this.domNode, {
handle: this.focusNode,
constraints: function() {
return dojo.coords(dojo.body());
}
});
}
});
Now you can use ConstainedFloatingPane instead of dojox.layout.FloatingPane:
var floatingPane = new ConstrainedFloatingPane({
title: "A Constrained Floating Pane",
resizable: true
}, searchboxNode);