I have a GetAnimal.vue file that contains this:
<template>
<div>
<form v-on:submit.prevent="getAnimal()">
<textarea v-model = "animal"
name = "animal" type="animal" id = "animal"
placeholder="Enter your animal here">
</textarea>
<button class = "custom-button dark-button"
type="submit">Get animal</button>
</form>
<button class="custom-button" v-on:click = "goTo('/viewanimal')">
View animal
</button>
</div>
</template>
<script>
import axios from 'axios';
export default {
data: function () {
return {
name: 'defaultAnimal',
animal: {
name: 'Cat',
furColor: 'red',
population: '10000',
isExtinct: false,
isDomesticated: true
}
}
},
methods: {
goTo: function(path) {
// alert(path);
this.$router.push({ path });
},
getAnimal: function () {
alert("animals");
this.info = {
"fur-color": "yellow", "population": '51000', "isExtinct":
false, "isDomesticated": true
};
axios({
method: 'get',
url: 'http://localhost:8080/getanimal',
data: {
animal: this.animal
}
});
}
}
}
</script>
inside router.js it is mapped like this:
{
path: "/getanimal",
component: () => import('./views/GetAnimal.vue')
}
When I go to http://localhost:8080/getanimal in browser I see this:
(has some inherited styles from the App.vue)
When I click the Get Animal button it displays the animal alert and then I see this in console:
Why can't I send an axios request to the very page I'm currently at? Why do I get the 404 error and how should I fix it?
Related
I'm trying to send file from vue-page to server. For this I use:
FileFrom component:
<template>
<div class="FileForm" v-bind:name="name">
<label class="FileFormLabel">
{{ name }}:
<input type="file" files="files" v-on:change="fileUpload" v-bind:name="name"/>
</label>
<button class="SubmitBtn" v-on:click="submit">
Submit
</button>
</div>
</template>
<script>
export default {
name: 'FileForm',
props: ["value", "name"],
data: function() {
return {
files: [],
}
},
methods: {
fileUpload: function(event) {
this.$emit("upload", [event.target.files[0]])
},
submit: function() {
this.files = []
this.$emit("submit")
},
},
}
</script>
Page:
<template>
<Container>
<div class="content">
<h1>
Upload files
</h1>
<div class="forms">
<FileForm v-bind:files="files['Model']" name="Model" v-on:upload="upload_model" v-on:submit="submit_model">
</FileForm>
</div>
</div>
</Container>
</template>
<script>
import axios from 'axios'
import Container from '#/components/Container.vue'
import FileForm from '#/components/FileForm.vue'
export default {
name: 'App',
data: function() {
return {
files: {},
}
},
components: {
Container,
FileForm
},
methods: {
upload_model: function(file) {
this.files['Model'] = file
},
submit_model: function() {
let formData = new FormData();
formData.append('Model', this.files['Model']);
axios.post('http://' + document.location.host + '/api/upload_model', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
})
}
},
}
</script>
But sending request looks like this:
-----------------------------316537648527426258472746653245
Content-Disposition: form-data; name="Model"
[object File]
-----------------------------316537648527426258472746653245--
A file is not sent as file but as string "[object File]".
As far as I understand the problem is that FormData.append converts all non-Blob(or File) objects to string and this.files['Model'] is not this one. It is proxy object which Vue.js uses for reactivity.
How can I take the internal object from this proxy and use it for sending?
I changed
formData.append('Model', this.files['Model']);
to
formData.append('Model', this.files['Model'][0]);
in page code.
And now it works fine. I don't know, is it the way to get needed value from proxy or I just returned array of files instead of single file somewhere in my code, but it helped.
I am trying to integrate a third party js application to my vue.js project. It is a molecular editor that will load on my page as a component.
Link to the js application - https://jsme-editor.github.io/dist/index.html
And this is what I want to achive -
<html><head>
<script type="text/javascript" language="javascript" src="jsme/jsme.nocache.js"></script>
<script>
//this function will be called after the JavaScriptApplet code has been loaded.
function jsmeOnLoad() {
jsmeApplet = new JSApplet.JSME("jsme_container", "380px", "340px");
jsmeApplet.setAfterStructureModifiedCallback(showEvent);
document.getElementById("log").value = "";
}
function showEvent(event) {
var log = document.getElementById("log");
log.value = event.action + " at: " + event.atom + " b: " + event.bond + " m: " + event.molecule + " smiles:" + event.src.smiles() + "\n" + log.value;
}
</script></head>
<body>
<div id="jsme_container"></div>
<textarea id="log" rows="5" cols="50"> </textarea>
</body>
</html>
What I have done so far is I have declared it as component as seen below -
<template>
<div class="hello">
<button #click="notify">Notify</button>
<div id="jsme-container" ref="jsmeContainer"></div>
</div>
</template>
<script>
export default {
name: 'newcomp',
data() {
return {
jsmeIsLoaded : false,
div_select : null
}
},
props: {
txt: String,
height: {
type: String,
required: true
},
width: {
type: String,
required: true
},
smiles: String,
options: String,
onChange: Function
},
mounted() {
let script = document.createElement('script')
script.src = '/home/rathore/Desktop/test_component/src/assets/JSME_2020-12-26/jsme/jsme.nocache.js'
document.head.appendChild(script)
this.$nextTick(
window.jsmeOnLoad = () => {this.jsmeIsLoaded = true;}
)
},
watch: {
jsmeIsLoaded(){
this.div_select = this.$refs.jsmeContainer.id
const div_loader = document.createElement('script')
const applet_txt = 'jsmeApplet = new JSApplet.JSME("'+this.div_select+'","300px","400px");'
//console.log(applet_txt,this.div_select)
const div_applet = document.createTextNode(applet_txt);
div_loader.appendChild(div_applet);
document.head.appendChild(div_loader);
}
},
methods: {
//Unused method
handleJsmeLoad(){
if (this.props.options){
this.jsmeApplet = new window.JSApplet.JSME(this.div_select, this.props.width, this.props.height, {options: this.props.options});
}
else {
this.jsmeApplet = new window.JSApplet.JSME(this.div_select, this.props.width, this.props.height);
}
this.jsmeApplet.setCallBack("AfterStructureModified", this.handleChange);
this.jsmeApplet.readGenericMolecularInput(this.props.smiles)
},
handleChange(jsmeEvent){
if (this.props.onChange) {
this.props.onChange(jsmeEvent.src.smiles())
}
},
notify(){
if (this.jsmeIsLoaded){
alert("JSME LOADED!!");
}
}
},
}
</script>
and called the component -
App.vue
template>
<div id="app">
<newcomp :height="'300px'" :width="'400px'" :onChange="logsmile" />
</div>
</template>
<script>
import newcomp from './components/NewComponenet.vue'
export default {
name: 'App',
components: {
newcomp
},
methods: {
logsmile(smiles){
console.log(smiles)
}
},
}
</script>
Here I have tried injecting <script> tag in the <head>. It is injected as I expected, but it doesn't work it give me error -
Uncaught ReferenceError: JSApplet is not defined. and it doesn't render the editor.
but actually I want it render using handleJSMELoad() method. Please suggest me the resolution.
I'm new to Vue js - the following is not updating:
<div id="error" class="col s12 red center">
<span v-if="seen">
Error fetching readings: {{ msg }}
</span>
</div>
Vue:
var error = new Vue({
el: '#error',
data: {
msg: '',
seen: false
},
methods: {
show: function(message) {
this.msg = message;
this.seen = true;
},
hide: function() {
this.seen = false;
}
}
});
Post fetch:
fetch( ... )
.then(...)
.catch(err => {
error.show( err );
loader.hide();
});
error.show() displays the previously hidden div, but displays:
Error fetching readings: {}
Why?
i created a CodeSandbox sample based upon your code, you need to have computed property to have the Vue reactivity
Sample can be found, check code in HelloWorld.vue in components folder
https://codesandbox.io/s/x2klzr59wo
<template>
<div id="error" class="col s12 red center">
{{ seen }}
<hr />
<span v-if="computedSeen"> Error fetching readings: {{ msg }} </span>
<hr />
<button #click="show('effe');">SHOW</button>
<button #click="hide();">HIDE</button>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
msg: "",
seen: false
};
},
methods: {
show: function(message) {
this.msg = message;
this.seen = true;
},
hide: function() {
this.seen = false;
}
},
computed: {
computedSeen: function() {
// `this` points to the vm instance
return this.seen;
}
}
};
</script>
Oops, problem was err from the fetch is an object, and I should have used err.message.
In my code I had a console.log('Error: %s', err) which appears to format the err object into text. Which is what threw me :(
Sorry.
I am having trouble displaying product via product component.
First in my vue.js app, I load Products via ajax like so:
var app = new Vue({
el: '#app',
data: {
products: [] // will be loaded via Ajax
},
mounted: function () {
var self = this;
ajaxGetProducts(0, self); // ajax, to fetch products
},
methods: {
getProducts: function (event) {
let groupID = Number(document.getElementById("GroupSelect").value);
ajaxGetProducts(groupID, this);
}
}
});
//Ajax call to fetch Products
function ajaxGetProducts(groupID, self) {
$.ajax({
type: "POST",
url: "/Data/GetProducts",
data: { Id: groupID },
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
dataType: "json"
, success: function (response) {
self.products = response; // Loading products into the App instance
},
error: function (jqXHR, textStatus, errorThrown) {
self.products = [];
}
}).done(function () {
});
}
Then I display those produdcts, and it works just fine:
<!-- HTML -->
<div id="app">
<div v-for="prod in products" >{{prod.Id}}</div>
</div>
Question: if I want to use a component. How do I do that?
This is how my component looks so far:
Vue.component('product', {
props: [],
template: `<div>ProdID: {{product.Id}} {{product.Qty}}</div>`,
data() {
return {
Id: "test id"
}
}
})
Example Product object has following properties:
{
Id: 1,
Qty: 5,
Title: "Nike shoes",
Price: 200,
Color: "Green"
}
And eventually I would like to use it in HTML like so:
<!-- HTML -->
<div id="app">
<!-- need to pass prod object into product component -->
<div v-for="prod in products" >
<product></product>
</div>
</div>
I know that I have to pass the object via Component properties somehow?
Passing each property 1 by 1 is not a good idea, cause this product is subject to change, so property name can change, or be added more. I think there should be a way to pass a whole Product object to Product component somehow, right?
You can pass the information into your component via the props
something like this;
Vue.component('product', {
props: ['item'],
template: `<div>ProdID: {{item.Id}} {{item.Qty}}</div>`
})
and pass it on like this;
<div id="app">
<div v-for="prod in products" :key='prod.Id'>
<product :item='prod'></product>
</div>
</div>
What about passing it as
<product v-for="prod in products" :key="prod.Id" :product="prod"></product> and in the component: props: {product:{type: Object, required: true}}?
Then in the component template you can use things like {{product.Id}}
I want to autofill my input value with the value of my server, this works if I do not use vue, but since I use vue for other reasons it does not.
Vue overrides the value with an empty string how can my vue take that value and update it in my axios post.
<input type="text" id="title" name="title" value="{{ $snippet->title }}" v-model="title">
new Vue({
el: '#snippet-form',
data: {
title: '',
},
methods: {
publishSnippet (e) {
var self = this;
axios.post('/snippets', {
title: this.title,
})
.then(function (response) {
console.log("success");
})
.catch(function (error) {
console.log(error);
})
},
},
});
You have to use use props which allows you to pass a value to the component. The thing is, you can't use it on Vue root instance. You need to use components.
In your resources/assets/js/components/, create a folder/file SnipperForm/SnippetForm.vue.
SnippetForm.vue, will be like:
<template>
<form>
<input type="text"
id="title"
name="title"
v-model="title">
<button #click.prevent="publishSnippet()">Submit</button>
</form>
</template>
<script>
export default {
props: {
snippetTitle: {
type: String,
default: ''
},
},
data: {
title: '',
},
mounted() {
this.title = this.snippetTitle;
},
methods: {
publishSnippet () {
axios.post('/snippets', {
title: this.title,
})
.then(function (response) {
console.log("success");
})
.catch(function (error) {
console.log(error);
})
},
},
}
</script>
And finally, in your app.js:
Vue.component('snippet-form', require('SnippetForm/SnippetForm.vue'));
And your, again, in your app.js, edit your Vue instance:
const app = new Vue({
el: '#app',
});
And in your blade view, use the SnippetForm.vue component like:
<snippet-form snippet-title="{{ $snippet->title }}"><snippet-form>