Vue Bind Click On Classes - vue.js

I am a newbie in Vue.js.
In old jQuery, it was simple to bind a click on some classes:
$('body').on('click','some-class-*', function(e) {})
Bu how to do it in Vue? I read that I can make a bind on a single element like
<span v-bind:click="dosomething" classes="some-class-1"></span>

You can archive this with normal JS:
var mySelection = document.getElementsByClassName('some-class');
for(var i = 0; i < blockSelection.length; i++) {
(function(index) {
mySelection[index].addEventListener("click", function() {
// Do something
})
})(i);
}

Related

Which is the best way to use this script in the Vue.js?

I found a tutorial that covered the same functionality for Angular. Here is the code:
openModal() {
document.getElementById('imgModal').style.display = "block";
}
closeModal() {
document.getElementById('imgModal').style.display = "none";
}
plusSlides(n) {
this.showSlides(this.slideIndex += n);
}
currentSlide(n) {
this.showSlides(this.slideIndex = n);
}
showSlides(slideIndex);
showSlides(n) {
let i;
const slides = document.getElementsByClassName("img-slides") as HTMLCollectionOf < HTMLElement > ;
const dots = document.getElementsByClassName("images") as HTMLCollectionOf < HTMLElement > ;
if (n > slides.length) {
this.slideIndex = 1
}
if (n < 1) {
this.slideIndex = slides.length
}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[this.slideIndex - 1].style.display = "block";
if (dots && dots.length > 0) {
dots[this.slideIndex - 1].className += " active";
}
}
}
It directly changes class names and styles using document. Which is the best way to implement this functionality in vue.js?
Option 1 - $refs
For getting element from DOM use ref.
If you set in HTML for an element ref attribute, e.g. <button ref="myButton"> then you can change the style in the same way as in your code:
this.$refs.myButton.style.display="none"
Regarding loops: ref will help only if the elements with the same ref were created by v-for. In this case this.$refs.<your ref> will be an array. Example: let's say you have images displayed by v-for with the same ref:
<img v-for="image in images" ref="imgSlide"...>
Then you can manipulate this.$refs.imgSlide as an array:
this.$refs.imgSlide.forEach(el => el.style.display = 'none')
Option 2 - Class and Style Bindings
Let's say you have <img id='imgModal'...>. You want to change display in 'openModal' method.
Do the folowing steps:
Add style binding: <img id='imgModal' :style="{ display: displayValue }"...
Add binding variable in data and initialize it:
data: {
displayValue: 'none'
}
Change the value of binding variable in the method:
openModal() {
this.displayValue = 'block'
}
With this approach, you don't need loops to change the style for multiple elements. Changing the binding variable will affect all elements bound with it.
Read more about Class and Style Bindings
Specifically for display = "none": Don't hide elements by changing display explicitly. Use v-if or v-show instead.

Getting "cannot read proper 'popperRef' of undefined" while adding a tooltip for cytoscape(cy)nodes

Getting "cannot read proper 'popperRef' of undefined" while adding a tooltip for cytoscape(cy)nodes. I am using Vue.js and Cytoscape.js. Not
mounted() {
cytoscape.use(popper)
this.addTooltip()
}
methods : {
addTooltip() {
let makeTippy = function (nodeTemp, node) {
return tippy( node.popperRef(), {
content: function(){
var div = document.createElement('div');
div.innerHTML = text;
return div;
},
trigger: 'manual',
arrow: true,
placement: 'bottom',
hideOnClick: false,
interactive: true
} ).tooltips[0]
}
var nodes = this.cy.nodes();
for (var i = 0; i < nodes.length; i++) {
var tippy = makeTippy(nodes[i]);
tippy.show();
}
}
}
Follow the documentation: https://github.com/cytoscape/cytoscape.js-popper#usage-with-tippyjs
If you have trouble making things within your app and you're not comfortable with using a debugger, then you should try to reproduce your issue outside of your app in s simple demo that's easier for your to reason about.
Here are materials for learning how to use the browser's debugger: https://developers.google.com/web/tools/chrome-devtools/javascript/

How to access dynamic props inside a child component's ready() in VueJS

I have dynamically bind a parent's data to a child via dynamic props (objectives is an array which is fetched via AJAX):
<objective-selector :objectives="objectives"></objective-selector>
Inside the objective-selector's ready() hook, I wish to do some pre-processing and somehow this.objectives is an observable, not an array:
Vue.component('objective-selector',{
template: '#objective-selector-template',
data:function() {
return {
current_selected:0
}
},
ready:function(){
// set current selected to the first non-active objective
for (var i =0; i < this.objectives.length; ++i) {
if (this.objectives[i].active == false) {
this.current_selected = i;
break;
}
}
},
props: ['objectives']
});
Everything else works fine (I can use the objectives props as array in the template, for instance). How do I access it as an array inside ready()?
Your ready function is fired sequentially before the ajax response comes back from the server. So you need to fire the function afterward.
One easy way to do this is $broadcast when the value has returned from the parent.
compiled: function(){
this.$on('theDataCameBackFromTheServer',function(){
for (var i =0; i < this.objectives.length; ++i) {
if (this.objectives[i].active == false) {
this.current_selected = i;
break;
}
}
});
}
Another solution would be to use watch (this will fire every time objectives changes):
watch: {
objectives: function(){
for (var i =0; i < this.objectives.length; ++i) {
if (this.objectives[i].active == false) {
this.current_selected = i;
break;
}
}
}
}

Dojo populate combo box widget dynamically

Could someone please explain to me why this simple straight forward code isnt working,
var serviceStore = new dojo.data.ItemFileWriteStore({
data: {identifier: "serviceCode",items:[]}
});
//jsonObj is a json object that I obtain from the server via AJAX
for(var i = 0; i<jsonObj.length;i++){
serviceStore.newItem({serviceCode: jsonObj[i]});
}
var serviceFilterSelect = dojo.byId('serviceSelect');
serviceFilterSelect.store = serviceStore;
There is no error at all displayed but my combobox with the id "serviceSelect" doesn't display any options, the combo is declared in the html section of my code,
<input dojoType = "dijit.form.ComboBox" id="serviceSelect"></input>
Any pointers towards the right direction will be much appreciated.
First of all you should use dijit.byId to get dojo widget instead of dojo.byId.
Also every item in jsonObj should contains field "name". This field will be displayed in combobox. E.g:
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require("dijit.form.ComboBox");
var storeData = {
identifier: 'serviceCode',
items: []
}
var jsonObj = [{
serviceCode: 'sc1',
name: 'serviceCode1'
},
{
serviceCode: 'sc2',
name: 'serviceCode2'
}]
dojo.addOnLoad(function () {
var serviceStore = new dojo.data.ItemFileWriteStore({ data: storeData });
for (var i = 0; i < jsonObj.length; i++) {
serviceStore.newItem(jsonObj[i]);
}
var serviceFilterSelect = dijit.byId('serviceSelect');
serviceFilterSelect.attr('store', serviceStore);
});
And HTML:
<select dojotype="dijit.form.ComboBox" id="serviceSelect" ></select>
It seems that it works.
I can't tell from the code you posted, but if you're having trouble getting the DOM nodes, they may not had a chance to get loaded.
You can try wrapping what you have above with a dojo.ready(function(){ ... });.
Have you put items in your store? I can't tell from the sample that you posted.
var serviceStore = new dojo.data.ItemFileWriteStore({
data: {
identifier: "serviceCode"
,items: [
{serviceCode:'ec', name:'Ecuador'}
,{serviceCode:'eg', name:'Egypt'}
,{serviceCode:'sv', name:'El Salvador'}
]
}
});
For dojo >= 1.6:
dojo.byId('serviceSelect').store=serviceStore;
For dojo < 1.6:
dojo.byId('serviceSelect').attr("store",serviceStore);

looping through DOM / mootools sortables

I can't seem to get a handle on my list of sortables. They are a list of list elements, each with a
form inside, which I need to get the values from.
Sortables.implement({
serialize: function(){
var serial = [];
this.list.getChildren().each(function(el, i){
serial[i] = el.getProperty('id');
}, this);
return serial;
}
});
var sort = new Sortables('.teams', {
handle: '.drag-handle',
clone: true,
onStart: function(el) {
el.fade('hide');
},
onComplete: function(el) {
//go go gadget go
order = this.serialize();
alert(order);
for(var i=0; i<order.length;i++) {
if (order[i]) {
//alert(order[i].substr(5, order[i].length));
}
}
}
});
the sortables list is then added to a list in a loop with sort.addItems(li); . But when I try to get the sortables outside of the sortables onComplete declaration, js says this.list is undefined.
Approaching the problem from another angle:
Trying to loop through the DOM gives me equally bizarre results. Here are the firebug console results for some code:
var a = document.getElementById('teams').childNodes;
var b = document.getElementById('teams').childNodes.length;
try {
console.log('myVar: ', a);
console.log('myVar.length: ', b);
} catch(e) {
alert("error logging");
}
Hardcoding one li element into the HTML (rather than being injected via JS) changes length == 1, and allows me to access that single element, leading me to believe that accessing injected elements via the DOM is the problem (for this method)
Trying to get the objects with document.getElementById('teams').childNodes[i] returns undefined.
thank you for any help!
not sure why this would fail, i tried it in several ways and it all works
http://www.jsfiddle.net/M7zLG/ test case along with html markup
here is the source that works for local refernece, using the native built-in .serialize method as well as a custom one that walks the dom and gets a custom attribute rel, which can be your DB IDs in their new order (I tend to do that)
var order = []; // global
var sort = new Sortables('.teams', {
handle: '.drag-handle',
clone: true,
onStart: function(el) {
el.fade('hide');
},
onComplete: function(el) {
//go go gadget go
order = this.serialize();
}
});
var mySerialize = function(parentEl) {
var myIds = [];
parentEl.getElements("li").each(function(el) {
myIds.push(el.get("rel"));
});
return myIds;
};
$("saveorder").addEvents({
click: function() {
console.log(sort.serialize());
console.log(order);
console.log(mySerialize($("teams")));
}
});