Error message from console stating that res is not defined - javascript

I am currently trying to build a fullstack application using javascript(node.js). My goal is to create a weather API with dummy data and everything was going well until I reached the end portion where I am trying to get the users search results to show up below the search box. I've tried using a fetch API from my main js file to retrieve data from my index.js file (which contains the server, imported data, etc.) but I continue to get an error message from the console stating that 'res' is not defined. 'res.data.city' is what I am using to acquire the input information from the user and render it to the screen but I keep getting told that it is not defined; I believe that it should be coming from the index.js file. Here is my code. (PLEASE be nice guys. I am a new developer and am just trying to better myself at programming.)
script.js file (main javascript file that is linked to html document)
const form = document.querySelector('form');
const textInput = document.getElementById('city');
let city = textInput.value;
textInput.addEventListener('input', (e) => {
city = e.target.value;
})
const getData = () => {
fetch('http://localhost:3000/weather/?city=' + city)
.then(res => {
return res.json();
})
.then(resData => {
console.log(resData)
}).catch((error) => {
console.log(error)
});
};
form.addEventListener('submit', (e) => {
e.preventDefault();
getData()
let location = document.querySelector('.cityName');
let celsius = document.querySelector('.celsius')
let fahrenheit = document.querySelector('.fahrenheit')
let error = document.querySelector('.error')
if(res.data.city) {
location.innerHTML = 'City: ' + res.data.city;
celsius.innerHTML = 'Temperature (C): ' + res.data['temperature (C)']
fahrenheit.innerHTML = 'Temperature (F): ' + res.data['temperature (F)'];
} else {
error.Message.innerHTML = 'SORRY! This city is not currently in our
database :{'
}
textInput.value = '';
})
index.js(file with the server running)
const express = require('express')
const app = express();
const cors = require('cors')
const fakeWeatherData = require('./data.js')
app.use(cors());
app.get('/weather', (req, res) => {
let cityName = req.query.city.toLowerCase();
for(let i = 0; i < fakeWeatherData.length; i++)
if(!cityName) {
res.send({"status": "error", "message": "Please enter a city name"})
} else if (cityName === fakeWeatherData[i].city.toLowerCase()) {
return res.send(fakeWeatherData[i])
}
res.send({"status": "error", "message": "Sorry! This city isn't in the database :{"})
})
index.html(main file that will be rendered to broswer)
<body>
<div class='main'>
<form>
<label for='city'>City:</label>
<div class='city-box'>
<input type='text' placeholder='Please enter a city' id='city' name='city' require>
</div>
<button type='submit'>CLICK</button>
</form>
</div>
<div class='error'></div>
<div class='weather'>
<h1 class='cityName'></h1>
<h4 class='celsius'></h4>
<h4 class='fahrenheit'></h4>
</div>
<script src="./js/script.js"></script>
</body>
</html>

#GaloisGirl is correct, res is not defined because you are not defining res within the scope of the anonymous function where you set the submit event listener.
Given that you're not already using async/await, seems best to stick with promise notation so it would look something like this:
form.addEventListener('submit', (e) => {
e.preventDefault();
let location = document.querySelector('.cityName');
let celsius = document.querySelector('.celsius')
let fahrenheit = document.querySelector('.fahrenheit')
let error = document.querySelector('.error')
getData()
.then((res) => {
if(res.data.city) {
location.innerHTML = 'City: ' + res.data.city
celsius.innerHTML = 'Temperature (C): ' + res.data['temperature (C)']
fahrenheit.innerHTML = 'Temperature (F): ' + res.data['temperature (F)']
} else {
error.Message.innerHTML = 'SORRY! This city is not currently in our database'
}
textInput.value = ''
})
})
And you'll also want to return the promise from getData
const getData = () => {
return fetch('http://localhost:3000/weather/?city=' + city)
...OTHER STUFF

Related

Django, how to update my following list using fetch and PUT in JavaScript?

I have a method in views.py that adds user to the following list,
I'm trying to make it work whenever I click on the button "follow" that I have added in JavaScript
How do I make my Follow button in JavaScript go to my views.py method onclick ?
views.py method.
def follow(request, profile_to_follow):
try:
user_to_follow = User.objects.get(username=profile_to_follow)
user_to_following = Profile.objects.get(user=request.user.id)
except User.DoesNotExist:
return JsonResponse({"error": "Profile not found."}, status=404)
if request.method == "PUT":
user_to_following.following.add(user_to_follow)
return HttpResponse(status=204)
urls.py
# API Routes
path("posts", views.compose_post, name="compose_post"),
path("posts/all_posts", views.show_posts, name="show_posts"),
path("posts/<int:post_id>", views.post, name="post"),
path("profile/<str:profile>", views.display_profile, name="profile"),
path("<str:profile_posts>/posts", views.display_profile_posts, name="profile_posts"),
path("follow/<str:user_to_follow>", views.follow, name="follow"),
JavaScript
function load_user_info(user_clicked_on){
document.querySelector('#page-view').style.display = 'none';
document.querySelector('#posts-view').style.display = 'none';
document.querySelector('#show-posts').style.display = 'none';
document.querySelector('#load-profile').style.display = 'block';
fetch(`/profile/${user_clicked_on}`)
.then(response => response.json())
.then(profile => {
const profile_element = document.createElement('div');
const followers = document.createElement('div');
const following = document.createElement('div');
const follow_button = document.createElement('button');
follow_button.innerHTML += "Follow";
followers.innerHTML = 'Followers: ' + profile.followers;
following.innerHTML = 'Following: ' + profile.following;
profile_element.appendChild(followers);
profile_element.appendChild(following);
profile_element.appendChild(follow_button);
profile_element.classList.add('profile_element');
follow_button.addEventListener("click", () => {
follow_user(user_clicked_on)
});
document.querySelector('#user-profile').appendChild(profile_element);
});
document.querySelector('#user-profile').innerHTML = `<h3>${user_clicked_on.charAt(0).toUpperCase() + user_clicked_on.slice(1)} Profile</h3>`;
}
function follow_user(user_to_follow){
// to make this function work with the one in views.py
fetch(`/profile/${user_to_follow}`, {
method: 'PUT',
})
}

jQuery Append only works in debug in Mozilla Firefox

I am using SignalR for Chat in my app. When a user connects, I use .append to add the users name to a div with a list of users. The code works fine in Chrome and Edge, but when I run it in FireFox the append does not work unless I hit F12 and run the code in debug mode.
Here is my javascript:
$(document).ready(function () {
initLoad = true;
loadRequests();
#Html.Raw(tabstr)
// Declare a proxy to reference the hub.
var chatHub = $.connection.chatHub;
$.connection.hub.start().done(function () {
registerEvents(chatHub)
});
registerClientMethods(chatHub);
});
function registerClientMethods(chatHub) {
chatHub.client.onNewUserConnected = function (connectionId, name, jobtitle) {
AddUser(chatHub, connectionId, name, jobtitle);
}
}
function AddUser(chatHub, connectionId, name, jobtitle) {
var userId = $('#hdId').val();
const connectionID = connectionId;
const userName = name;
const jobTitle = jobtitle;
const connectedUser = $("#divusers").append('<div id="' + connectionID + '" class="kt-widget__item" style="cursor:pointer"><div class="kt-widget__info"><div class="kt-widget__section"><a class="kt-widget__username">' + userName + '</a><span class="kt-badge kt-badge--success kt-badge--dot"></span></div>' + jobTitle + '</div></div>');
connectedUser.on("click", function () {
var groupWindows = [];
$('#groupWindowList').empty();
$('div[id^="ctr"]').each(function () { groupWindows.push(this.id); })
$.each(groupWindows, function (index, value) {
var controlname = value;
const groupName = controlname.replace("ctr", "")
const listItem = $(`<li>${groupName}</li>`);
listItem.on("click", function () {
$('#addToGroupModal').modal('toggle');
chatHub.server.addUserToGroup(groupName, connectionID);
});
$('#groupWindowList').append(listItem);
})
$('#addToGroupModal').modal({});
});
}
const connectedUser + $("#divusers").append is the problem. In debug, it is fine, but if I just run the code, the append does not take place and user's name does not display in the list.
Here is my html:
<div class="kt-portlet__body">
<div class="kt-widget kt-widget--users kt-mt-20">
<div class="kt-scroll kt-scroll--pull">
<div id="divusers" class="kt-widget__items">
</div>
</div>
</div>
</div>
UPDATE
So I added:
var myElement = $('#divusers')[0];
var observer = new MutationObserver(function(mutations) {
if (document.contains(myElement)) {
alert('hi');
});
observer.observe(document, {attributes: false, childList: true, characterData: false, subtree:true});
to check if the element exists in the DOM. I replaced the alert('hi') with the code to start the ChatHub and the append still does not work.
Another weird thing is if I make almost ANY change in the html and run it. It works the first time, but if I stop it and run it again. It doesn't work.
Any assistance is greatly appreciated.

JS: Instantiated variable won't recognise input value

I am instantiating a new variable from a class. The class has one constructor, city and then fetches jazz clubs through the foursquare API.
When I hard-code the city name into the instantiated class, it works fine. But when I want to feed it a dynamic value (a query from the search bar which I grab through the DOM), it won't recognise the city. Here is the code:
The Class:
class Venues {
constructor(city) {
this.id = '...';
this.secret = '...';
this.city = city;
}
async getVenues() {
const response = await fetch(`https://api.foursquare.com/v2/venues/search?near=${this.city}&categoryId=4bf58dd8d48988d1e7931735&client_id=${this.id}&client_secret=${this.secret}&v=20190309`);
const venues = await response.json();
return venues;
}
}
const input = document.getElementById('search-input').value;
const button = document.getElementById('button');
const jazzClubs = new Venues(input);
button.addEventListener('click', (e) => {
e.preventDefault();
getJazzVenues();
})
function getJazzVenues() {
jazzClubs.getVenues()
.then(venues => {
console.log(venues);
})
.catch(err => {
console.log(err);
});
}
Anyone knows why the the input variable's value is not recognised by the newly instantiated jazzClubs variable?
Also, if you have tips on how to structure this code better or neater, I'd welcome any suggestions (the class definition is in a separate file already).
Many thanks guys!
Adam
You need to make sure, the following statements are triggered after the button click.
const input = document.getElementById('search-input').value;
const jazzClubs = new Venues(input);
Also your code looks too complex. Use simpler code using jquery.
Try something like this:
$(document).ready(function() {
$("#search-button").click(function() {
var searchval = $("#search-input").val();
var id = "xxx";
var secret = "yyy";
alert(searchval);
var url = "https://api.foursquare.com/v2/venues/search?near=" + searchval + "&categoryId=4bf58dd8d48988d1e7931735&client_id=" + id + "&client_secret=" + secret + "&v=20190309";
alert(url);
$.ajax({
url: url,
dataType: 'json',
success: function(data) {
var venues = data.response.venues;
alert(venues);
$.each(venues, function(i, venue) {
$('#venue-result').append(venue.name + '<br />');
});
}
});
});
});
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<label>City:</label>
<input type="text" id="search-input" />
<button type="button" id="search-button">Search</button>
<div id="venue-result"></div>
</body>
</html>

window.location result is null

I want to build a website which returns products from a database and when click on See More, should return product details from server in another html page. The problem is that when I click See More, productID%20=%20null :(.
productDetails = second html page.
productDetails = div - in index.html where products are returned from server
<script>
var productsUrlList = 'https://finalonlineshop.firebaseio.com/.json';
async function getProductsFromServer() {
var productsResponse = await fetch(productsUrlList)
var products = await productsResponse.json();
return products;
}
async function showProducts(productsPromise) {
var products = await productsPromise;
var generatedHTML = '';
var productsIDs = Object.keys(products);
productsIDs.forEach(productID => {
var product = products[productID];
generatedHTML += getGeneratedHTMLForProduct(productID, product);
});
document.getElementById('categories').innerHTML = generatedHTML;
}
function getGeneratedHTMLForProduct(productID, product) {
var generatedHTML = `
<div id = categoriesDiv>
<img class = "categoryImage" src = ${product.Image} />
<div class = "categoryName">${product.Name}</div>
<div class = "categoryPrice">$ ${product.Price}</div>
<br>
<button id = "seeMore" onclick = "seeMore('${productID}')">See
more</button>
</div>
`;
return generatedHTML;
}
function seeMore (productID) {
window.location = `./productDetails.html?productID = ${productID}`;//issue
}
function getProductIDFromUrl () {
var params = new URLSearchParams(window.location.search);
var productID = params.get('productID');
return productID;
}
async function getDetailsFromServer(productID) {
var detailsResponse = await fetch(`https://finalonlineshop.firebaseio.com/Products/details/${productID}.json`);
var details = await detailsResponse.json();
return details;
}
async function seeDetails(detailsPromise) {
var details = await detailsPromise;
var generatedHTML = `
<div id = "detailsAboutProduct">
<img src = "${details.Image}" /> //Cannot read property "Image" of null
<div>${details.Name}</div>
<div>${details.Details}</div>
<div>$ ${details.Price}</div>
<div>${details.Qty}</div>
<button id = "addToCart" onclick = "addToCart();">Add to
cart</button>
</div>
`;
document.getElementById('details').innerHTML = generatedHTML;
}
</script>
get rid of the spaces around the = in the URL, that gets encoded as %20. You should also use encodeURIComponent() to escape any special characters in the product ID.
function seeMore (productID) {
window.location = `./productDetails.html?productID=${encodeURIComponent(productID)}`;
}
Your query to your firebase app seems to be wrong.
you are fetching : https://finalonlineshop.firebaseio.com/Products/details/${productID}.json
which return null
but you have to fetch: https://finalonlineshop.firebaseio.com/${productID}.json
instead and it will return the right object

Pebble configuration page communications not responding

I'm creating my first watchface which requires a configuration page where two strings can be stored (a title and a message).
I'm not too familiar with all the communication things because there aren't really any full on examples out there but I've tried to get as far as possible with this.
Here is the relevant code to all my spaces
main.c
static void inbox_received_callback(DictionaryIterator *iterator, void *context) {
APP_LOG(APP_LOG_LEVEL_INFO, "Message received!");
// Get the first pair
Tuple *t = dict_read_first(iterator);
//Long lived buffers
static char title_buffer[64];
static char message_buffer[124];
// Process all pairs present
while(t != NULL) {
// Process this pair's key
switch (t->key) {
case TITLE_DATA:
snprintf(title_buffer, sizeof(title_buffer), "%s", t->value->cstring);
text_layer_set_text(title_layer, title_buffer);
APP_LOG(APP_LOG_LEVEL_INFO, "TITLE_DATA received with value %d", (int)t->value->int32);
break;
case MESSAGE_DATA:
snprintf(message_buffer, sizeof(message_buffer), "%s", t->value->cstring);
text_layer_set_text(message_layer, message_buffer);
APP_LOG(APP_LOG_LEVEL_INFO, "MESSAGE_DATA received with value %d", (int)t->value->int32);
break;
}
// Get next pair, if any
t = dict_read_next(iterator);
}
}
pebbleScript.js
var title = localStorage.getItem('title') ? localStorage.getItem('title') : 'Title',
message = localStorage.getItem('message') ? localStorage.getItem('message') : "Message that can be changed in watchface 'Settings'";
Pebble.addEventListener('showConfiguration', function(e) {
console.log("Showing configuration");
// Show config page
Pebble.openURL('https://dl.dropboxusercontent.com/s/kzl44khedt5e22d/config.html?dl=0');
});
Pebble.addEventListener('webviewclosed', function(e) {
var options = JSON.parse(decodeURIComponent(e.response));
title = encodeURIComponent(options.title);
message = encodeURIComponent(options.message);
if(title == 'undefined') {
title = 'Title';
} if (message == 'undefined') {
message = "Message that can be changed in watchface 'Settings'";
}
localStorage.setItem('title', title);
localStorage.setItem('message', message);
console.log("Configuration window returned: ", JSON.stringify(options));
});
Pebble.addEventListener('ready', function(e) {
console.log("PebbleKit JS Ready!");
//Construct a dictionary
var
dict = {
'TITLE_DATA' : title,
'MESSAGE_DATA' : message
};
//Send a string to Pebble
Pebble.sendAppMessage(dict, function(e) {
console.log("Send successful.");
}, function(e) {
console.log("Send failed!");
});
});
config.html
<h3>Title:</h3>
<input type="text" name="title" id="title"></input>
<h3>Message:</h3>
<input type="text" name="message" id="message"></input>
<br>
<input type="submit" id="cancelButton" value="Cancel">
<input type="submit" id="saveButton" value="Save">
<script>
$('#cancelButton').click(function() {
location.href = 'pebblejs://close';
});
$('#saveButton').click(function() {
var options = {
title: $('title').val(),
message: $('#message').val()
}
location.href = 'pebblejs://close#' + encodeURIComponent(JSON.stringify(options));
});
function getURLVariable(name) {
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)",
regex = new RegExp(regexS),
results = regex.exec(window.location.href);
if (results == null) return "";
else return results[1];
}
$(document).ready(function() {
var priorTitle = getURLVariable('title');
priorTitle = decodeURI(priorTitle);
if (priorTitle) {
$('#title').html(priorTitle);
}
var priorMessage = getURLVariable('message');
priorMessage = decodeURI(priorTitle);
if (priorMessage) {
$('#message').html(priorMessage);
}
});
</script>
If anyone can see why this isn't working as intended I'd much appreciate help :) Please let me know if there are any other details I should include.
I'm using CloudPebble for the development. I've done the title and message keys in settings and defined them in my main.c as well so it's not that.
A note that I should make is, in the app log it shows "TITLE_DATA received with value....." but not the "MESSAGE_DATA received...." So the problem may lie somewhere over there.
You're declaring your "long lived buffers" inside the function:
static void inbox_received_callback(DictionaryIterator *iterator, void *context) {
...
//Long lived buffers
static char title_buffer[64];
static char message_buffer[124];
...
}
If you want them to stay in scope (persist), you need to declare them up with the other globals:
static Window *s_main_window;
static char title_buffer[64];
static char message_buffer[124];

Categories