I wrote this Vue.JS code to display JSON response received from PHP file in a conversation format. My current code looks like this:
const app = new Vue({
el: "#chatview",
data: {
messages:[],
txtInput: '',
mid:0
},
methods:{
GetBubbleType: function (name){
if(name === "AI")
return "yours messages";
else
return "mine messages";
},
},
mounted(){
axios.post('./ConversationGetter.php',{
function2call: 'getRecord',
id: 1,
}).then( response => {console.log(response.data);
this.data=response.data;
}).catch(error => {});
},
template: `
<div style ="font-family:Open Sans;font-size:16px">
<div v-for="message in messages">
<div class="fade-in">
<div v-bind:class="GetBubbleType(message.name)">
<div class="message last">
<p>{{message.message}}</p>
</div>
</div>
</div>
</div>
<form #submit.prevent="sendMessage('out')" id="person-form">
<p>
<input type="text" placeholder="Enter Your Query Here"style=" border-radius=25px" v-model="txtInput">
</input>
<input type="submit" placeholder="Send"style=" border-radius=25px">
</input>
</p>
</form>
</div>
`
})
The response recieved from PHP is (written on console):
{
"data": [
{
"Modified_Time": "2019-12-13T16:08:36+05:30",
"$currency_symbol": "$",
"Message": "Hey!",
"Created_Time": "2019-12-13T16:08:36+05:30",
"Name": "AI",
},
{
"Modified_Time": "2019-12-13T16:08:27+05:30",
"$currency_symbol": "$",
"Message": "Yo!",
"Created_Time": "2019-12-13T16:08:27+05:30",
"Name": "Me",
},
],
}
The return line of PHP is: echo $result; return $result;
For some reason, it does not show the messages in the chat view.. Where am I going wrong?
Your template is doing a v-for on the messages object from the component's data. However, you're assigning this.data=response.data. That's creating a property data on the component instance, not assigning the messages value.
Instead, just change this.data=response.data to this.messages=response.data.data.
As noted in the comments, your response body contains a data array at the root, and Axios returns the response body in response.data, hence response.data.data is what should be assigned to this.messages.
Related
{
"user": "someuser",
"message": "need a help"
},
{
"user": "bot",
"message": "can i help you?"
},
{
"user": "someuser",
"message": "another question"
}
I need to read additional paragraphs on the page and add them to my json - object, for sending to the server. The positions can be around 10-20!
.edited-phrase and .phrase-return is what is already on the page in .client-mess and .bot-mess I fill in the data from json. Sending ajax is not a problem, the problem is to form correct data(
The final version should look like this:
{
"user": "someuser",
"message": "need a help"
"edited": "hello",
"return": "return on step_1",
},
{
"user": "bot",
"message": "can i help you?"
}
{
"user": "someuser",
"message": "another question"
"edited": "forget",
"return": "return on step_3",
},
Thank you in advance!
<div class="message-row">
<div class="client-say">
<p class="client-mess" data-user="someuser">need a help</p>
<div class="return-container">
<p class="edited-phrase">hello</p>
<p class="phrase-return">return on step_1</p>
</div>
</div>
</div>
<div class="message-row">
<div class="bot-say">
<p class="bot-mess" data-user="bot">can i help you?</p>
</div>
</div>
<div class="message-row">
<div class="client-mess data-user="someuser"">
<p class="phrase-return">another question</p>
<div class="return-container">
<p class="edited-phrase">forget</p>
<p class="phrase-return">return on step_3</p>
</div>
</div>
</div>
<div class="">
<a id="sendJson" href="#" class="" >send Json</a>
</div>
</div>
$('#sendJson').on('click', function() {
var messagesArray = [];
$dialogMessages = {};
$(".container .message-row")
.each(function () {
$dialogMessages = {
user:$(this).data('user'),
/* message:$(this).text(),
phraseEdited: ,
phraseReturn: , */
}
messagesArray.push($dialogMessages);
});
})
In browser environment, you can use querySelectorAll method:
const paragraphsWithClassReturn = document.querySelectorAll('p.return');
See querySelectorAll on MDN.
After this, you can turn the result into an array and loop through it using available array methods:
Array.from(paragraphsWithClassReturn).forEach(paragraph => {
// your code doing something with every found paragraph
})
In jQuery, you select elements having return class using
const $paragraphsWithClassReturn = $('p.return')
...and then loop through them with .each method:
$paragraphsWithClassReturn.each($paragraph => {
// your code doing something with every found paragraph
});
I've written a form that has a n amount of steps, and after parsing the data into string object (to put inside the request body) inside JavaScript, I want to load it up and send it to my Flask backend server.
{
"0": {
"function": "go_to_url",
"values": {
"url": "https://valid.url/"
}
},
"1": {
"function": "refresh",
"values": {
"amount": "5"
}
},
"2": {
"function": "take_screenshot",
"values": {
"name": "screenshotname"
}
},
"3": {
"function": "send_keys_to_element",
"values": {
"xpath": "//*[#value='login']",
"keysToSend": "loginname"
}
},
"4": {
"function": "assert_element_exist",
"values": {
"xpath": "//button[#login]"
}
}
}
This is what I want to send with onclick function within a button inside mentioned form. My Js call looks like this
function submitScenario() {
const steps = Array.from(document.getElementsByClassName('scenario-creation-step'));
const data = {};
for (const c in steps) {
var currentStep_dict = {};
currentStep_dict['function'] = steps[c].childNodes[0].value;
let inputs = Array.from(steps[c].childNodes[1].getElementsByTagName('input'));
var values = {};
for (const i in inputs) {
values[inputs[i].getAttribute('data')] = inputs[i].value;
}
currentStep_dict['values'] = values;
data[c] = currentStep_dict;
}
var dataJson = JSON.stringify(data);
console.log(dataJson);
fetch(window.location.href + 'ed',
{
method: 'POST',
headers: {
'Content-Type':'application/json',
},
body: dataJson,
}
);
}
The form presents itself like that, with url set for 'scenario_added'
<form action="{{ url_for('scenario_added') }}" method="post" name="scenarioForm">
<!-- inputs hidden for data being fetched from flask -->
<input type="hidden" id="scenario_name" value="{{ scenario_details[0] }}" />
<input type="hidden" id="expected" value="{{ scenario_details[1] }}" />
<input type="hidden" id="author_id" value="{{ scenario_details[2] }}" />
<input type="hidden" id="steps_to_show" value="{{ step_names }}" />
<div id="scenario-creation-table" class="scenario-creation-table">
<button type="button" id="add_step">Add a step</button>
<!-- steps show here -->
</div>
<div class="scenario-creation-submitbuttons">
<div></div>
<div></div>
<input type="button" id="download_json" value="Pobierz scenariusz">
<input type="submit" id="submit_scenario_button" value="Dodaj Scenariusz" onclick="submitScenario()">
</div>
The view for scenario_added looks as follows:
#app.route("/scenario_added", methods = ["GET", "POST"])
def scenario_added():
if request.method == "GET":
return '<h6>bad request, it was get for /scenario_added</h6>' #TODO 404
scenario_data = request.json
return render_template('scenario_added.html', data = scenario_data)
Unfortunately, after sending such request, I'm presented with "Bad Request
Did not attempt to load JSON data because the request Content-Type was not 'application/json'."
Even though, when I send the request via POSTMAN on the url, I receive a 200 Code with expected result of the html view containing the data.
How should I rearrange the form or JavaScript function so it will send a request with data gathered from the form?
Browser Console Error
Uncaught ReferenceError: getNewCars is not defined at HTMLDivElement.onclick
Code Explained
I'm building a car selector form. How it works is there's categories (known as seasons) that can be clicked on to bring up a list of specific cars that pertain to that category (season).
Html
<div class="chooseCar">
<div class="chooseCarTabs">
</div>
<div class="chooseCarWrapper">
<div id="chooseCarSelection">
</div>
</div>
</div>
<script src="/public/theme/scripts/car-selection.js"></script>
car-selection.js
alert('new car-selection js')
let cars;
let seasons = [
{
"name": "Seasonal Cars",
"path": "seasonal.json"
},
{
"name": "Modern Cars",
"path": "modern.json"
},
{
"name": "Classic Cars",
"path": "classic.json"
},
{
"name": "Flag Cars",
"path": "flags.json"
}
];
let seasonTab = "Seasonal Cars";
const chooseCarBody = document.getElementById('chooseCarSelection');
const seasonsTabs = document.getElementsByClassName('chooseCarTabs')[0];
function loadCars(){
chooseCarBody.innerHTML = '';
cars.forEach(car => {
chooseCarBody.innerHTML += `
<div class="singleCar">
<div class="singleCarInner">
<img src="/public/images/avatars/${car.filename}" alt="${car.name}">
</div>
</div>
`
})
}
//Ajax Request
async function setSeasons() {
seasonsTabs.innerHTML = ''
await seasons.forEach(season => {
seasonsTabs.innerHTML += `
<div ${seasonTab == season.name ? 'class="activeSeasonTab"' : ''} onclick="getNewCars('${season.name}', '${season.path}' )">
${season.name}
</div>
`
});
}
//Will be replaced with AJAX Request
async function getNewCars(seasonName, season = seasons[0].path){
cars = null;
await fetch(`/public/data/cars/${season}`)
.then(response => response.json())
.then(data => {
console.log(data)
seasonTab = seasonName;
cars = data; console.log(cars)
})
.catch(error => console.log(error));
await loadCars()
}
async function initData(){
await setSeasons();
await getNewCars(seasons[0].name);
}
initData();
Extra code explanation
let cars; and let seasons work as a state of sorts. When a seasons tab is clicked on an ajax request is sent to get fill the cars state with cars for the category which is then looped through and populated on the page.
My Problem
When I reload the page the cars and category (season) tabs appear on the page just fine including the getNewCars(). But when I go to click on:
<div
${seasonTab == season.name ? 'class="activeSeasonTab"' : ''}
onclick="getNewCars('${season.name}', '${season.path}' )"
>
${season.name}
</div>
I get this error:
Uncaught ReferenceError: getNewCars is not defined at HTMLDivElement.onclick
Note, inline scripts I don't seem to get this error:
<div class="chooseCar">
<div class="chooseCarTabs">
</div>
<div class="chooseCarWrapper">
<div id="chooseCarSelection">
</div>
</div>
</div>
<script> /* All scripts in here*/</script>
How do I fix this and what's going wrong with my code that when import from another js file this happens?
I am trying to make a zomato random restaurant generator, so whenever you put your city it gives a random restaurant in that city. I made api for it and it works perfectly, this is a sample output of the api call
{
"name": "Natural Ice Cream",
"url": "https://www.zomato.com/ncr/natural-ice-cream-rajouri-garden-new-delhi?utm_source=api_basic_user&utm_medium=api&utm_campaign=v2.1",
"location": {
"address": "J 2/10, BK Dutt Market, Rajouri Garden, New Delhi",
"locality": "Rajouri Garden",
"city": "New Delhi",
"city_id": 1,
"latitude": "28.6474674597",
"longitude": "77.1195488423",
"zipcode": "",
"country_id": 1,
"locality_verbose": "Rajouri Garden, New Delhi"
},
"price": 1,
"thumbnail": "https://b.zmtcdn.com/data/pictures/8/313368/da7c191473cdc9701aa97a8cbcd51255.jpg?fit=around%7C200%3A200&crop=200%3A200%3B%2A%2C%2A",
"rating": "4.7"
}
the backend linking frontend to backend looks like this
searchForm.addEventListener('submit', async e => {
e.preventDefault();
resultArea.innerHTML = '';
const query = e.target.querySelector('#restaurant-name').value;
if (query === '') {
return
}
e.target.querySelector('#restaurant-name').value = '';
const res = await fetch(`${hostname}/locations/${query}`, {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
method: 'POST',
})
const json = await res.json();
populateData(json);
});
function populateData(results) {
results.forEach(result => {
const newResult = rTemp.content.cloneNode(true);
newResult.querySelector('.result-title').innerText = result.name;
newResult.querySelector('.result-neighborhood').innerText = result.location.locality;
newResult.querySelector('.result-address').innerText = result.location.address;
newResult.querySelector('.result-price').innerText = '$'.repeat(result.price);
newResult.querySelector('.result-thumbnail').src = result.thumbnail;
newResult.querySelector('.result-website').href = result.url;
resultArea.appendChild(newResult);
});
}
here rTemp is querySelector('template') and resultArea is querySelector('#restaurant-results') and hostname is this.location.origin
And lastly this is the frontend
<body>
<div class="wrapper">
<main>
<h1>Restaurant <span>Random</span></h1>
<form action="">
<div class="form-wrapper">
<label for="restaurant-name">Search</label>
<input name="restaurant-name" type="text" id="restaurant-name" placeholder="City Name">
</div>
<input type="submit">
</form>
</main>
<hr>
<section id="restaurant-results">
</section>
</div>
<template>
<div class="result-card">
<div class="result-header">
<h2 class="result-title">${title}</h2>
<h3 class="result-location result-neighborhood">${neighborhood}</h3>
<h3 class="result-location result-address">${address}</h3>
<p class="result-price">${price}</p>
</div>
<div class="result-body">
<img src="" alt="restaurant-photo" class="result-thumbnail">
</div>
<div class="result-footer">
<button class="result-footer-button">Call</button>
<button class="result-footer-button">Visit Website</button>
<button class="result-footer-button">Make Reservation</button>
</div>
</div>
</template>
<script src="index.js"></script>
</body>
When I run this I get the following error
POST http://127.0.0.1:5500/locations/delhincr 405 (Method Not Allowed)
(anonymous) # index.js:16
index.js:16 is
const res = await fetch(`${hostname}/locations/${query}`, {
and
Uncaught (in promise) SyntaxError: Unexpected end of JSON input
at HTMLFormElement. (index.js:22) which is
const json = await res.json();
I am unable to locate the error. How do I solve these?
I'm trying to get results from an api based on the user search box. When the user enters a value 'en' or 'de'. They should get the result from that search. I need to bind the user input into my query string. This works when I manually code the country into the template, but not when I bind the value into the string after the user inputs a value for the second time. The 'get' request that uses the user input value 'query' works fine. But not when I bind this a second time
I want to be fit to access
results[i].query.name
But '.query' is not working when I query the data unless I enter the value manually '.en'
I have a json file that looks like the following
[
{
"en": {
"name": "testone",
"id": 5363289,
"location": "messages_en.properties1"
},
"de": {
"name": "testonede",
"id": 5363289,
"location": "messages_en.properties2"
}
},
{
"en": {
"name": "test2",
"id": 5363289,
"location": "messages_en.properties3"
},
"de": {
"name": "test2de",
"id": 5363289,
"location": "messages_en.properties4"
}
}
]
Below is my index.html vue.js template
<div id=#app>
<input type="text" v-model="query" placeholder="Choose Language" />
<div class="medium-6 columns">
<a #click="getResult(query)" class="button expanded">Retrieve</a>
</div>
<template v-for="(result, i) in results">
<div class="card" style="width: 20rem; display:inline-block;">
<div class="card-block"></div>
<p> {{results[i].query}} </p>
<!-- works when I manually code in the 'en' query but when ran with 'query' it returns an error 'Cannot read property 'name' of undefined"' second time it returns that the value is -->
<!-- <p> {{results[i].en.name}} </p> -->
<!-- <p> {{results[i].query.name}} </p> -->
</div>
</template>
</div>
Vue.js
el: '#app',
data () {
return {
search: '',
query: 'en',
results: '',
title: '',
items: '',
section: ''
}
},
methods: {
getResult(query) {
axios.get('http://localhost:3000/api/country?country=' + query + '&blank=true').then(response => {
this.results = response.data;
console.log(this.results);
});
},
You need to use bracket notation to access a property using a param, so:
results[i][query].name
The second issue is that results[i][query] will be undefined until the async call has completed, so you will need to check that the property is not undefined or use a boolean flag. So, to check that it is not undefined you could do something like:
<p v-if="!!results[i][query]">{{results[i][query].name}}</p>
<p v-else>Loading...</p>
Here's a simplified JSFiddle for that: https://jsfiddle.net/4w3dxm22/
Or you could just use a dataLoaded flag:
new Vue({
el: '#app',
methods:{
getResult(query) {
this.dataLoaded = false; // set dataLoaded to false
axios.get('http://localhost:3000/api/country?country=' + query + '&blank=true').then(response => {
this.results = response.data;
this.dataLoaded = true; // Data has loaded so set dataLoaded to true
});
},
data: {
dataLoaded: false
}
})
Then you can do:
<span v-if="dataLoaded">{{results[i][query].name}}</span>
<span v-else>Loading Data...</span>
Here's the simplified JSFiddle for that: https://jsfiddle.net/99ydx82u/