Completely stop displaying a div by using conditionally rendering - vue.js

There is this one thing that is bothering me. I have this one line of code which uses the "v-if" tag, it is used to hide one of the menu items after you've used a setup tool.
The problem here is that when you load up the page, it will display the menu item for half a second first which should be hidden directly from the start. How can I achieve this?
Here is the code:
<li><button v-show="!configCompleted" class="btn" #click="setComponent('setup')">Setup</button></li>
beforeMount lifecycle hook:
beforeMount() {
this.setComponent(this.$route.params.page)
this.user = JSON.parse(localStorage.getItem('vue-laravel-ecommerce. d fuser'))
axios.defaults.headers.common['Content-Type'] = 'application/json'
axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('vue-laravel-ecommerce.jwt')
axios.get('/api/shop').then( response => {
if ( response.data.length ) {
this.configCompleted = true
}
});
},

That's because you modify this.configCompleted when you get the response from api, which takes some time. You can probably just set the default value of it to true in data()
data() {
return {
configCompleted: true,
...
}
}

Related

(Vue 3) Error: AG Grid: cannot get grid to draw rows when it is in the middle of drawing rows

-- Initial setup --
Create component
const ButtonAgGrid= {
template: "<button>{{ displayValue }}</button>",
setup(props) {
const displayValue = 'TEST-TEXT';
return {
displayValue,
};
},
};
Register component
<AgGridVue
:components="{
ButtonAgGrid
}"
...
/>
Pass data
const columnDefs = [
{
field: "name"
},
{
field: "button",
cellRenderer: "ButtonAgGrid",
}
]
const rowData = computed(() => {
return {
name: testReactiveValue.value ? 'test', 'test2'
}
})
And when computed "rowData" updated, agGrid send error:
Error: AG Grid: cannot get grid to draw rows when it is in the middle of drawing rows. Your code probably called a grid API method while the grid was in the render stage. To overcome this, put the API call into a timeout, e.g. instead of api.redrawRows(), call setTimeout(function() { api.redrawRows(); }, 0). To see what part of your code that caused the refresh check this stacktrace.
But if we remove cellRenderer: "ButtonAgGrid", all work good
My solution is to manually update rowData.
watchEffect(() => {
gridApi.value?.setRowData(props.rowData);
});
This one works well, but I wish it was originally

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)

VUE.js Refreshing img scr after submitting a form

I'm facing the following issue with vue.js2.
After submitting a form, I want to refresh image src.
When the form is submitted, a new image with a chart is generated in the back-end.
This new chart image replaces the old one, however, the URL stays the same.
To update image, I'm using v-bind on image src and bind it to one of the data variables.
The starting image which is displayed before submitting the form is placeholder.jpg.
After receiving a response, I call changeChart method to update it with graph.jpg.
This action works and image is updated
The problem I'm facing here is when I update one of the values and click submit again, the image does not change.
However, when I click clear method first and set chart_url to placeholder.jpg again on next submit, image changes properly.
<v-img
v-bind:src=this.chart_url
</v-img>
<script>
export default {
name: "CenterComponent",
data: function () {
return {
value1: "",
value2: "",
value3: "",
output: null,
chart_url: "http://127.0.0.1:5000/media/pictures/placeholder.jpg",
}
},
methods:{
clear(){
this.value1 = "";
this.value2 = "";
this.value3 = "";
this.output = "";
this.chart_url = "http://127.0.0.1:5000/media/pictures/placeholder.jpg";
},
changeChart(){
this.chart_url = "http://127.0.0.1:5000/media/pictures/graph.jpg"
},
submitForm(){
fetch("http://127.0.0.1:5000/predict",{
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
value1: this.value1,
value2: this.value2,
value3: this.value3
})
}
).then(response => {
if (response.ok) {
return response.json();
}
}).then(data => {
this.output = data["prediction"];
this.changeChart();
});
}
},
};
</script>
As you say, the first time you're submitting the form you actually change the url from 'placeholder.jpg' to 'graph.jpg', and on subsequent submits it remains as 'graph.jpg'.
This means that the browser is not going to fetch that image again every time it changes to 'graph.jpg' as it is cached. To make the browser fetch a new image you can try cache-busting by appending a random number to the end of the url in your changeChart method. You're effectively telling the browser that it doesn't have this image, so go fetch it.
changeChart(){
const randomNumber = Math.floor(Math.random() * 1000)
this.chart_url = `http://127.0.0.1:5000/media/pictures/graph.jpg?cachebust=${randomNumber}`
},
This will append a random number between 1-1000, but you could obviously improve this depending on your use case.
Alternatively, create a unique image name on the server when it is processed, and return this new name in the response of the POST call. That way you won't have this issue to start with.

vuejs dynamically adding class

Using vuejs 3. In the vuejs app, I have:
data(){
return{
return_prohibited:false
}
}
return_prohibited turns to true when the server returns an error message from a fetch request:
fetch(myUrl,this.myInit)
.then(response => response.json())
.then(data => {
if (data.message) {
this.credits = []
this.debits = []
return_prohibited = true
} // cut for brievity
Html file:
<button #click="previousMonth" id="bouton_mois_prec" :class="{interdit:return_prohibited}" >précédent</button>
I was expecting that the css class interdit would be added to the button each time that return_probibited is true, as per these explanations. But nothing happens.
You should append this. in front of return_prohibited - otherwise you will get errors in the console.

How to change the value of a prop (or data) of a component, from OUTSIDE the component?

As the title says, I'm trying to change the value of a prop/data in a component, but the trigger is being fired from outside the component, from something that has nothing to do with Vuejs.
Currently I trying to use a Simple State Manager, based on the docs from here, like so:
var store = {
debug: true,
state: {
progress: 23
},
setProgress (uff) {
if (this.debug) console.log(uff)
this.state.progress = uff
}
}
The documentation leads me to believe that if the value of progress is mutated, the value of my Vue instance would also change if I link them accordingly. But this doesn't work in a component (my guess would be it's cause it's a function).
This is part of my component:
Vue.component('transcoding', {
data () {
return {
progress: store.state.progress
}
},
template: `
<v-progress-circular
:size="130"
:width="25"
:value="progress"
color="teal"
>
{{progress}}
</v-progress-circular>
`
})
So, when I trigger a store.setProgress(value), nothing happens. The log messages do happen, but the state isn't updated in the component.
This is the script that's currently triggering the state change:
App.cable.subscriptions.create(
{ channel: "ProgressChannel", room: "2" },
{ received: function() {
store.setProgress(arguments[0])
}}
)
It's an ActionCable websocket in Ruby on Rails. The trigger works perfectly, but I just cannot make the connection between the state change and the component.
I tried loading this script in the mounted() event for the component, thinking I could reference the value like this:
Vue.component('transcoding', {
data () {
return {
progress: 0
}
},
template: `
<v-progress-circular
:size="130"
:width="25"
:value="progress"
color="teal"
>
{{progress}}
</v-progress-circular>
`,
methods: {
setProgress: function(uff) {
this.progress = uff
}
},
mounted() {
App.cable.subscriptions.create(
{ channel: "ProgressChannel", room: "2" },
{ received: function() {
this.setProgress(arguments[0])
}}
)
}
})
But this gives me an error saying that this.setProgress is not a function, which is obvious since I'm calling it within the create method of App.cable.subscriptions.
How can I make this work? I realize I'm mixing things with my question, but I wanted to illustrate what my goal is. I simply want to know how to make the component's progress data to update, either from the outside, or from the component itself if I can make it find the function.
You are initializing your data item to the value from the store:
data () {
return {
progress: store.state.progress
}
}
Changes to the store will not propagate to your data item. You could eliminate the data item and just use store.state.progress where you need it, or you could create an computed that returns its value if you want a local single-name handle for it.