# [Vue.js] List directory contents with Apache

Let me start by saying that my knowledge of Apache is almost none, so I apologize if when not using the correct terminology.

there is a website written in Vue, and the routing is taken care by vue.js Router. In their documentation, they specify that in order for the router to work correctly, you have to put this in the .htaccess file of the website:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$- [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] </IfModule> From what there is been able to understand, all requests are sent back to the index.html file which will take care of loading the correct component based on the path. My goal is to now allow my website to have a path (let’s say /documents) which is not picked up by Vue, but instead shows the contents of the directory and allows you to both navigate and download the contents (Like this). there is tried a few ways, but they all return a 403 or 500 (possibly due to a mistake in my config). I understand that I need to add a RewriteRule but all of those that I tried return weird errors. Thanks in advance ### Solution : You can have multiple rewrite rules based on what the RewriteBase is . In the current set, the rule is applying to the root of the host. You can add another rule with RewriteBase /documents/. More info: What does RewriteBase do and how to use it? ### Solution 2: I recommend reading the docs: https://httpd.apache.org/docs/2.4/mod/mod\_rewrite.html The RewriteCond directive defines a rule condition. So here a dirty explanation: RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d So the RewriteConds says that if the given path/url isn’t a file (!-f) and not a directory (!-d) then the next rewrite rule (RewriteRule . /index.html [L]) takes action. RewriteRule . /index.html [L] “.” is a wildcard, so all urls will be redirect to index.html. The [L] flags stops the execution (https://httpd.apache.org/docs/2.4/rewrite/flags.html#flag\_l) The RewriteRule ^index\.html$ - [L] stops the execution if the url is index.html.

So, the rewrite rule fulfill the requirements and seems correct.

When you get a 403 you maybe need to add Options +Indexes to the config or htaccess.

### Solution 3:

In the end, after looking through the docs, I was not able to understand how to set it up. I found this page, and using option #2 I was able to get the directory to at least show up.

TLDR

Create the folder in the location you want. In my case it was in httpdocs/documents
Create a .htaccess file where you put the following contents:

# Omit this section if you do not need the auth
AuthType Basic
AuthName “restricted area”
AuthUserFile /path/to/your/.htpasswd
require valid-user

Order allow,deny
Allow from all
Options +Indexes

Create the .htpasswd file in the location you specified above. To generate the username/password combo I used this

Any corrections are welcome!

# [Vue.js] Is it good practice to use for loops to sort out data in the same function where it's fetched in Vue?

when using fetch to get some data from an API, I convert this to JSON and want to sort it into different categories. For example tickets (which is what I’m retrieving) with the status active should be in a different array than the ones with status waiting on customer. to use a for loop to sort through the results. Should I do this in the same function they’re fetched in?

Did a bit of googling but couldn’t find a post on this.

methods: {
fetchTickets() {
fetch(‘/api’)
.then(res => res.json())
.then(resJson => {
arrayLength = resJson.length
for(var i = 0; i < arrayLength; i++) {
if(resJson[i][‘status’] === ‘active’) {
//do something
}
else if(resJson[i][‘status’] === ‘waiting on customer’) {
// do something else
}
else {
// do a dance
}
}
});
},
}

So, is it okay to do the above or is it very sensitive to errors/is there a more convenient alternative?

### Solution :

There is a more convient alternative.

You should create two API calls.

1.) /api/activeUsers
2.) /api/waitingCustomers

Then for each API call, you can use the .filter API and return the appropiate array

fetchActiveTickets() {
fetch(‘/api’)
.then(res => res.json())
.then(resJson => {
return resJson.filter(item => {
return item.status ===’active’
})
//do the same for waiting… i.e. resJson(item => {
//return item.status ===’waiting’
//})

}
});
},

### Solution 2:

I would recommend using .filter() rather than looping over the array to split the source into the pieces you want.

data: {
activeTickets: [],
waitingTickets: []
}
methods: {
fetchTickets() {
fetch(‘/api’)
.then(res => res.json())
.then(resJson => {
this.activeTickets = resJson.filter(function(ticket) { return ticket.status === ‘active’ });
this.waitingTickets= resJson.filter(function(ticket) { return ticket.status === ‘waiting on customer’ });

// do things with the filters arrays…

});
},
}

### Solution 3:

Try

methods: {
async fetchTickets() {
let res = await (await fetch(‘/api’)).json();
let active = res.filter(x=> x[‘status’]==’active’);
let waiting = res.filter(x=> x[‘status’]==’waiting on customer’);
// … do something
},
}

# [Vue.js] How to make sure that the DOM elements I want to manipulate have loaded before trying to do anything with them in Vue.js?

I’ve been battling this problem since yesterday and I’m at my wits end. Currently, there is a method in vue.js file that does this:

methods: {
showSlides(n) {
let slides = document.getElementsByClassName(“mySlides”);

slides[0].style.display = “block”;
}
},
mounted(){
this.showSlides();
}

It finds all elements with the class of “mySlides”, stores them in a variable and then attempts to change the style of the first element. This function is called when the component is mounted().

Now, the problem is that I get an error which states “TypeError: Cannot read property ‘style’ of undefined”. Turns out that at the time of execution of this function, these DOM elements are undefined. I realized this by adding a @click=’showSlide()’ event to a button. When I click the button, the function runs successfully, however, when it is mounted() it doesn’t.

The code also works successfully in a plain HTML file where the script is at the bottom of the page. This is what leads me to believe that something fishy is going on.

Full Code:

<template>
<div class=”wrapper”>
<div class=”sight-container”>
<p class=’sight-name’>{ sight.name }</p>
<p>{ sight.formatted_phone_number }</p>
<p>{ sight.international_phone_number }</p>
<p>{ sight.website }</p>

<div class=”photos-container”>
<div v-for=’(image, index) in sightImages’ class=”mySlides”>
<div class=”numbertext”>{ index + 1 } / { sightImages.length }</div>
<img class=’sight-photos’ :src=”‘https://maps.googleapis.com/maps/api/place/photo?maxwidth=1920&photoreference=' + image.photo_reference + ‘&key=’”>
</div>

<a class=”prev” @click=’plusSlides(-1)’></a>
<a class=”next” @click=’plusSlides(1)’></a>

<div class=”caption-container”>
<p id=”caption”></p>
</div>

<div class=”row”>
<div v-for=’(image, index) in sightImages’ class=”column”>
<img class=”demo cursor” :src=”‘https://maps.googleapis.com/maps/api/place/photo?maxwidth=1920&photoreference=' + image.photo_reference + ‘&key=’” style=”width:100%” @click=”currentSlide(1)”>
</div>
</div>
</div>

</div>
</div>
</template>

<script>
import axios from ‘axios’

export default {
data(){
return {
placeId: this.$route.params.placeid, sight: “”, sightImages: [], slideIndex: 1 } }, methods: { showSlides(n) { let i; let slides = document.getElementsByClassName(“mySlides”); let dots = document.getElementsByClassName(“demo”); let captionText = document.getElementById(“caption”); 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”; dots[this.slideIndex-1].className += “ active”; captionText.innerHTML = dots[this.slideIndex-1].alt; }, plusSlides(n) { this.showSlides(this.slideIndex += n); }, currentSlide(n) { this.showSlides(this.slideIndex = n); } }, mounted(){ axios.get(‘/getSight/‘ + this.placeId) .then(response => { this.sight = response.data.result.result this.sightImages = response.data.result.result.photos }).catch((error) => console.log(error)); this.showSlides(this.slideIndex); } } </script> ### Solution : That’s because you’re using it wrong. Normally, mounted are called after rendering component’s DOM, at this time component’s this.$el is ready to be used.

However, in mounted you’re calling asynchronous operation that updates data (and later DOM) upon completion, but you try to use its result before it happened.

It should be like this:

mounted() {
axios.get(‘/getSight/‘ + this.placeId)
.then(response => {
this.sight = response.data.result.result;
this.sightImages = response.data.result.result.photos;
this.nextTick(() => { this.showSlides(this.slideIndex); }); }).catch((error) => console.log(error)); } Small hint: rather than use el.className += … and el.className.replace(…) you can use el.classList.add(…) and el.classList.remove(…). Docs: Element.classList # [Vue.js] Input field not reacting to data changes after being written to by a user While creating a Vue.js application there is become stuck at a weird problem. to be able to manipulate an input field (think increment and decrement buttons and erasing a zero value on focus, so the user doesn’t have to) and up until a user writes to the input field, everything is fine. After that, however, further changes in the data are no longer represented in the input field. As I was sure I could not be the only one with this particular problem, I searched extensively, but had no luck. What baffles me the most is that everything works until the field is written to, since I can not really imagine why this would remove the data binding. The following code should show the same behavior. It is an input field component, which is initialized with a zero value. On focus the zero gets removed. This works, until a user manually writes to the field after which zero values will no longer be removed, even though the focus method fires, the if-condition is met and the data in the amount-variable is changed. Vue.component(‘item’, { data: function () { return { amount: 0 } }, render: function (createElement) { var self = this; return createElement(‘input’, { attrs: { //bind data to field value: self.amount, type: ‘number’ }, on: { //update data on input input: function (event) { self.amount = event.target.value; }, //remove a zero value on focus for user convenience focus: function (event) { if (self.amount == 0 || self.amount == “0”) { self.amount = ‘’; } } } }) } }) ### Solution : I think you need to use domProps instead of attrs to make it reactive. But I would suggest you use vue’s template syntax or if you insist on using the render function I would also suggest you to use JSX. # [Vue.js] How to fix the columns size in different screen resolutions using vuetify grid I’m creating a simple dashboard using vue.js and Veutify. I choose to structure the layout using the grid system available in vuetify’s library. The problem is that I can’t get the same look depending on the screen resolution. Is there any way to have the left container always with the width of the side drawer? I already try to set the max-width of the side bar manually in 300px, but did’nt work. <v-container grid-list-md text-xs-center> <v-layout row wrap> <v-flex xs3 class=”side”> <SideBar/> </v-flex> <v-flex xs9 class=”main” > <MainPage/> </v-flex> </v-layout> </v-container> I expect I got edit: HTML/CSS generated: https://pastebin.com/bLYgv5pz ### Solution : The short answer is that the 3-column area is designed to always be 25% of the container width for grids like this. If you want to keep the sidebar the size of the 3-column section, you can give it max-width:100%; I’m not familiar with the exact styling used by Vuetify, but if you can post the generated HTML and CSS, it should certainly be possible to suggest how you might restrict the growth of that column. # [Vue.js] VueJS Set variable name using string Is it possible to set a variable myvar using a string in the example below ? <script> export default { data() { return { myvar: ‘foo’ }; } } </script> I tried this which didn’t work: eval(‘myvar’): ‘foo’ ### Solution : Here is a very crude and basic example of how you would accomplish something like this: new Vue({ el: “#app”, data() { return { myVar: ‘hello’ } }, methods: { changeVal(varName, newValue) { this[varName] = newValue; } } }); <script src=”https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id=”app”> {myVar} <button @click=”changeVal(‘myVar’, ‘world’)”>change myVar</button> </div> Here, we are utilizing a method that takes the name of the variable and the value to change it to - then passing it to the current vue.js model instance (represented by this inside of methods) to modify the value of the dynamic variable name. ### Solution 2: To change data, you just need to modify it like you would any other mutable variable. It depends how the component is set up. Looking at the docs (https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties), one way of doing it is like this (modified example from the above link): const vue.js = new Vue({ el: ‘#app’, data: { myvar: ‘foo’ }, template: ‘<div>{ myvar }</div>’ }) vue.myvar = ‘bar’ <script src=”https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id=”app”></div> If you want to do it from a method (e.g. calling a method from within a template), refer to it with the this keyword: const vue.js = new Vue({ el: ‘#app’, data: { myvar: ‘foo’ }, template: ‘<div><div>{ myvar }</div><button @click=”changeMe”>Click Me</button></div>’, methods: { changeMe() { this.myvar = ‘bar’ } } }) <script src=”https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id=”app”></div> # [Vue.js] vuetify card without left and right margin when new to vue.js and vuetify and just use v-card tag from vuetify. that the v-card have 100% width, (without left or rigth side spacing) Is there any configuration that can be made on these initial tags ? <v-layout column justify-center align-center \> <v-flex xs2 sm2 md2 \> How can it ben done ? I try : .section{ padding-top: 100px; padding-bottom: 100px; width:100%; } and : <div class=”section section_dark”>services</div> But still there is some left and right space for this div. ### Solution : You can try row instead of column : <v-layout row justify-center align-center \> and use special props for card : <v-card min-width=”100%” \> # [Vue.js] Jump to position on click (access class from other Vue component) Explanation of problem If a user clicks on the login link the view shall jump down to the login window where a user can type in userdata. when aware how to do this within a single file using document.getElementById(‘login-window’).scrollIntoView() However, there is a project with various single Vue.js component files. The login-link is within one “label” component. But the actual login-window is located in another component called “loginWindow”, thus also the id / class “login-window” is stored in “loginWindow”. I tried to grab the “login-window” element with getElementById within my “label” component, but I believe it cannot access it since it is in another component. This is the template code from “loginWindow” <template> <LoginGrid class=”login-window” :as-grid=”true” :class=”classes” autocomplete=”off”> <OCard class=”login-card” :border=”false”> <div class=”login-headline f-copy f-bold l-color-primary”>{ t(‘headline’) }</div> <!– online state –> <template v-if=”isLogged”> <OButton color=”secondary” @click=”onClickLogout”>{ t(‘logout-label’) }</OButton> </template> <!– offline state –> <template v-else> <div class=”login-inputs”> <LoginInput class=”login-input-card-number” /> </div> <OLink type=”secondary” class=”login-mode-link f-regular f-copy-small” :no-router=”true” @click=”onSwitchMode” \> { modeLabel } </OLink> </template> </OCard> </LoginGrid> </template> Here is what I’ve tried exactly Within my “label” component there is implemented this method with an else-statement: export default { name: ‘loginWindow’, methods: { onClick() { if (this.isLogged) { } else { if (isBrowser) { document.getElementById(“login-window”).scrollIntoView(); } } }, }, } So if the user is not logged-in, then onClick() it should scroll to the id of “login-window”. However, this solution does not work. I get an error saying “Cannot read property ‘scrollIntoView’ of null”. Any ideas how to do this with JavaScript within a Vue.js component? ### Solution : login-window is Class not ID in the HTML. Try this: document.querySelector(“.login-window”).scrollIntoView(); # [Vue.js] Adsense injecting style tag into my page (in chrome) when working on a website that is heavily front-end (vue) and thus when using the async version of adsense. When testing in various browsers I noticed a display issue in chrome where the height of my page was being changed immediately after ads loaded. Hours later I discovered that within show_ads_impl.js it is injecting style=”height: auto !important;” (or similar) into various places in my source code. I could not find help on this anywhere and am desperate to find a solution - this really impacts the user experience within my project quite negatively. I asked for help on the adsense support website and did not get a single response. I was successful at removing the style attribute added by the ads with a delayed callback routine in my javascript - but as you can imagine that caused the page to flicker in a way that is certainly unpleasant. https://pagead2.googlesyndication.com/pagead/js/r20190408/r20190131/show\_ads\_impl.js Note the link above will not contain the “injection” code unless you download it from chrome. The code in question in the file above looks like this: a.o && !c && f && (e.setProperty(“height”, “auto”, “important”), d && !v(String(d.minHeight)) && e.setProperty(“min-height”, “0px”, “important”),
d && !aw(String(d.maxHeight)) && e.setProperty(“max-height”, “none”, “important”))) : (Yv(a, 1, l, c, “height”, h, a.B, a.l),

### Solution :

For anyone that may stumble on this in the future. Below is how I was able to “solve” the problem in a way that I deemed good enough to move on.

Like I stated above, google Adsense was injecting style=”height: auto !important; min-height: 0px !important;” into my primary page wrapper element on my website.

Below is the code I used to solve the problem - essentially undoing what Adsense does.

// this code listens for a mutation on the main-wrapper element and resets
// the style attribute back to “null”.
// This is necessary because Google Adsense injects style into this main-wrapper
// element changing its height properties. Note: This only occurs in Chrome.
let wrapper = document.getElementById(‘main-wrapper’)
const observer = new MutationObserver(function (mutations, observer) {
wrapper.style.height = ‘’
wrapper.style.minHeight = ‘’
})
observer.observe(wrapper, {
attributes: true,
attributeFilter: [‘style’]
})

# [Vue.js] CKFinder issue Uncaught TypeError Cannot read property 'modal' of undefined with CKEditor 5 - Vue js

I’m trying to integrate CKFinder in vue.js js application. But facing this issue Uncaught TypeError: Cannot read property ‘modal’ of undefined.

I’m following the official documentation for CKEditor5 / CKFinder for vue.js js.

Here the ckfinder configuration.

ckfinder: {
// Define the CKFinder configuration (if necessary).
options: {
resourceType: ‘Images’
},
}

Here’s the complete error message shown in the browser console.

Uncaught TypeError: Cannot read property ‘modal’ of undefined
at CKFinderCommand.execute (ckfindercommand.js?9ed3:153)
at CKFinderCommand.eval (observablemixin.js?3466:268)
at CKFinderCommand.fire (emittermixin.js?e4c7:236)
at CKFinderCommand.(:9191/anonymous function) [as execute] (webpack-internal:///./node_modules/@ckeditor/ckeditor5-utils/src/observablemixin.js:296:19)
at CommandCollection.execute (commandcollection.js?e961:92)
at ClassicEditor.execute (editor.js?7e01:299)
at ButtonView.eval (ckfinderui.js?8a75:47)
at ButtonView.fire (emittermixin.js?e4c7:236)
at TemplateToBinding.eval (buttonview.js?d175:167)
at ProxyEmitter.callback (template.js?56c1:1208)

### Solution :

You need to attach CKFinder to the page first, so CKEditor 5 can use it.

The easiest way to do so is by using a script tag:

<script src=”https://example.com/ckfinder/ckfinder.js"></script>