11521 sujets

JavaScript, DOM et API Web HTML5

Bonjour
j'ai une erreur :
Erreur : SyntaxError: Unexpected end of input
(ligne 100)
avec ce code que je teste :

index.html
  <body>

        <div><button id="ask-weather">Quelle est la météo sur Paris ?</button></div>
        <div id="weather-result"></div>

    <script src="sm.js" type="text/javascript"></script>
  </body>


sm.js

document.querySelector("#ask-weather").addEventListener('click', function () {

    let url = `https://www.prevision-meteo.ch/services/json/paris`;

    fetch(url, {
      mode: 'no-cors'
    })
      .then((response) =>
        response.json())
        .then((data) => {

          console.log(data);

          document.querySelector('#weather-result').innerHTML = "Votre choix";
          const result = document.getElementById("weather-result");
          const sousresult = document.createElement("p");
          result.appendChild(sousresult);
          sousresult.innerHTML += data.current_condition.condition;
        })

      .catch(err => console.log('Erreur : ' + err));

});


Donc au clic du bouton html j'essaie de faire apparaître la météo...

Si jamais vous pouvez m'aider ? Merci Smiley langue !
Modifié par woubi (30 Sep 2020 - 12:55)
Modérateur
Bonjour,

<del>J'opterais pour un problème de localisation de fichier ... n’étant pas sur le même domaine.
L'erreur : "Erreur : SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data" indique qu'il n'y a probablement aucune donnée de récupérée (confirmer ou non par ton console.log(data) ).</del>

edit : probleme majeure relevé par Styk : la propriété mode: 'no-cors' , enfin penser à lancer les script, qui se basent sur le DOM, après le chargement de la page.

Leurs services proposent, une Iframe mais pas d'utiliser AJAX ou pHp avec file_get_contents() ce qui te permet ensuite de traiter en local/sur le même domaine le fichier json. fraichement copié.

Cdt
Modifié par gcyrillus (30 Sep 2020 - 17:20)
Hello,

Ceci fonctionne très bien Smiley cligne


<!DOCTYPE html>
<html>

	<head>
		
		<script>
			
			const getMeteo = async function () {

				const ResponseData = await fetch('https://www.prevision-meteo.ch/services/json/paris');
				const Response = await ResponseData.json();
				alert(Response.current_condition.condition);

			};
			
		</script>

	</head>

	<body>
		
		<div><button id="ask-weather" onclick="getMeteo();">Quelle est la météo sur Paris ?</button></div>
		<div id="weather-result"></div>

	</body>
	
</html>
Ah au passage j'ai trouvé tes erreurs !
Déjà ton document.querySelector("#ask-weather") se lançait avant que la balise ne soit créée, donc il faut le placer dans un onload.
Ensuite ta propriété mode: 'no-cors' pose un souci, si tu relis la doc de fetch:

JavaScript ne peut accéder à aucune propriété de la Response

C'est ennuyeux Smiley lol

Voici ton code corrigé Smiley cligne


<!DOCTYPE html>
<html>

	<head>
		
		<script>
		
			document.addEventListener('DOMContentLoaded', function(){
				
				document.querySelector("#ask-weather").addEventListener('click', function () {

					fetch('https://www.prevision-meteo.ch/services/json/paris')
					  .then((response) =>
						response.json())
						.then((data) => {

						  console.log(data);

						  document.querySelector('#weather-result').innerHTML = "Votre choix";
						  const result = document.getElementById("weather-result");
						  const sousresult = document.createElement("p");
						  result.appendChild(sousresult);
						  sousresult.innerHTML += data.current_condition.condition;
						  
						})

					  .catch(err => console.log('Erreur : ' + err));

				});
				
			});
			
		</script>

	</head>

	<body>
		
  <body>

        <div><button id="ask-weather">Quelle est la météo sur Paris ?</button></div>
        <div id="weather-result"></div>

  </body>

	</body>
	
</html>
Meilleure solution
Modérateur
Ah, en effet pas vu le code executé avnt la fin du chargement, cependant , ton premier code m'a fait réagir sur le await et le mode asynchrone.

Du coup, voici une idée/approche similaire avec une fonction réutilisable basé sur le HTML suivant :
 <div>
   <button class="ask-weather" data-ville="paris">Quelle est la météo sur</button>
 </div
>

const request = async (el, ville) => {
  const response = await fetch(
    "https://www.prevision-meteo.ch/services/json/" + ville
  );
  const json = await response.json();
 // console.log(json);
  el.insertAdjacentHTML(
    "afterend",
    "<p>" + json.current_condition.condition + "</p>"
  );
};

let requestMeteo = document.querySelectorAll(".ask-weather");
for (let i = 0; i < requestMeteo.length; i++) {
  requestMeteo[i].addEventListener("click", function () {
    let ville = this.getAttribute("data-ville");
    request(this, ville);
  });
}

la fonction peut-être réutilisé en lui fournissant les deux variables, l'endroit ou ajouter le paragraphe (el) et la ville (ville) . Cela peut-être un option/select , un input , etc...

codepen de demo : https://codepen.io/gc-nomade/pen/bGpyOZm
Oui voilà, je pense que c'est vers ce chemin que se dirige notre ami Smiley biggrin .

C'est pour ça que sur mon codepen proposé en exemple j'utilise un input pour choisir l'importe quelle ville, ça évite d'avoir une page pleine de bouton Smiley lol

Sur ce principe j'avais fait une page météo en direct en simple HTA Smiley murf
(fichier à nommer en .HTA)

upload/1601479977-79129-capture.jpg


<!DOCTYPE html>
<html>
 
	<head>
		<meta http-equiv='refresh' content='300'; url='Weather.hta'>
		<meta http-equiv="X-UA-Compatible" content="IE=9">
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<title>My Weather by Stryk.</title>
   
      <script>
     
         // PURE JS - NO LIBRARY REQUIRED
		window.resizeTo(700, 670);
		
		window.onload=function(){
		
			DisplayTime();
			setInterval(DisplayTime,1000);
		
		} // END FUNCTION
		
		function DisplayTime(){

			lD = new Date(),
			document.getElementById("thistime").innerHTML = lD.toLocaleString();

		} // END FUNCTION
		
		document.addEventListener('DOMContentLoaded', function(){

			var ThisSelect = 'icon';
			InitMap(ThisSelect);

		}); // END DOCUMENT READY FUNCTION
		
		function InitMap(ThisSelect){
			
			var CityList = [
				['paris', 360, 201],
				['amiens', 357, 145],
				['brest', 105, 225],
				['metz', 505, 193],
				['toulouse', 322, 509],
				['marseille', 486, 510],
				['lille', 388, 113],
				['rouen', 305, 168],
				['caen', 263, 188],
				['rennes', 206, 239],
				['nantes', 210, 292],
				['bordeaux', 243, 419],
				['pau', 241, 512],
				['perpignan', 377, 549],
				['montpellier', 420, 503],
				['nice', 564, 485],
				['reims', 432, 184],
				['angers', 251, 277],
				['poitiers', 284, 329],
				['limoges', 320, 379],
				['avignon', 463, 483],
				['grenoble', 501, 410],
				['orleans', 338, 257],
				['tours', 299, 283],
				['nancy', 509, 214],
				['dijon', 464, 289],
				['lyon', 461, 375],
				['strasbourg', 570, 212],
				['mulhouse', 556, 264],
				['besancon', 511, 288],
				['bastia', 637, 542],
				['ajaccio', 615, 583],
				['bourges', 367, 300],
				['cahors', 329, 461],
				['clermont-ferrand', 386, 381],
				['chambery', 510, 386],
				['le mans', 278, 249],
				['aurillac', 363, 418],
				['montelimar', 455, 446],
				['troyes', 430, 241],
				['moulins', 403, 337],
				['cherbourg', 205, 157],
				['lorient', 144, 264],
				['niort', 253, 349]
			]; // END ARRAY

			for ( var IndexCity in CityList ){

				if (CityList[IndexCity][0]){
				
					createElement(CityList[IndexCity][0]);
					InitPositionElement(CityList[IndexCity][0], CityList[IndexCity][1], CityList[IndexCity][2]);
					GetActualWeatherInfo(CityList[IndexCity][0], ThisSelect);
				
				} // END IF

			} // END FOR
			
		} // END FUNCTION
		
		function createElement(ThisId){

			var NewDiv = document.createElement("div");
			NewDiv.id = ThisId;
			NewDiv.className = 'city';
			document.body.appendChild(NewDiv);

		} // END FUNCTION
		
		function InitPositionElement(ThisCity, ThisLeft, ThisTop){
		
			if (ThisCity){
			
				ThisElement = document.getElementById(ThisCity);
				ThisElement.style.left = ThisLeft + 'px';
				ThisElement.style.top = ThisTop + 'px';
				
			} // END IF
		
		} // END FUNCTION
		
		// ex
		//  https://api.openweathermap.org/data/2.5/weather?q=paris, FR&appid=cb1ff1bb13abb1825268598fb2b06b52
		function GetActualWeatherInfo(ThisCity, ThisSelect){
			
			var appid = 'cb1ff1bb13abb1825268598fb2b06b52';
			var url = 'https://api.openweathermap.org/data/2.5/weather?q='+ThisCity+',FR&appid='+appid;
			var xhr = new XMLHttpRequest();
			xhr.open("GET", url, true);
			xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
			xhr.send();
			xhr.onreadystatechange = function() {

				if (this.readyState == 4 && this.status == 200){

					var Response = JSON.parse(this.responseText);
					var ThisTemp = Math.round(Response.main.temp - 273) + '°';
					var ThisIcon = 'http://openweathermap.org/img/w/' + Response.weather[0].icon + '.png';
					var ThisPressure = Response.main.pressure;
					var ThisHumidity = Response.main.humidity + '%';
					var ThisWindSpeed = Math.round(Response.wind.speed * 3.6) + 'km/h';
					
					if ( ThisSelect == 'icon' ){ document.getElementById(ThisCity).innerHTML = '<img class="icon" src="' + ThisIcon + '"></img>'; }
					if ( ThisSelect == 'temp' ){ document.getElementById(ThisCity).innerHTML = ThisTemp; }
					if ( ThisSelect == 'pressure' ){ document.getElementById(ThisCity).innerHTML = ThisPressure; }
					if ( ThisSelect == 'humidity' ){ document.getElementById(ThisCity).innerHTML = ThisHumidity; }
					if ( ThisSelect == 'speed' ){ document.getElementById(ThisCity).innerHTML = ThisWindSpeed; }
					if ( ThisSelect == 'name' ){ document.getElementById(ThisCity).innerHTML = ThisCity; }

					RepositionElement(ThisCity);
					
				} //END IF

			}; // END XHR FUNCTION
		
		} // END FUNCTION
		
		function RepositionElement(ThisElementName){
		
			var ThisElement = document.getElementById(ThisElementName);
			var ThisWidth = ThisElement.clientWidth;
			var ThisHeight = ThisElement.clientHeight;
			var ThisLeft = ThisElement.offsetLeft;
			var ThisTop = ThisElement.offsetTop;
			var ThisNewLeft = ThisLeft - ( ThisWidth / 2 );
			var ThisNewTop = ThisTop - ( ThisHeight / 2 );
			ThisElement.style.left = ThisNewLeft + 'px';
			ThisElement.style.top = ThisNewTop + 'px';
		
		} // END FUNCTION

      </script>
	  
	  	<HTA:APPLICATION
		SINGLEINSTANCE = "Yes"
		MAXIMIZEBUTTON = "No"
		MINIMIZEBUTTON = "No"
		SHOWINTASKBAR = "Yes"
		ICON = "resmon.exe"
		BORDER = "Thin"
		BORDERSTYLE = "Complex"
		SCROLL="No"
		>
     
   </head>
 
   <body>
   
		<style>
			body {margin: 0px; padding: 0px}
			.city, #select, #logo, #thistime {position: fixed; z-index:2; text-align: center}
			#logo {width: 20%; height: auto; top: 10px; left: 530px}
			#thistime { padding: 5px; border-radius: 5px; background-color: #02539A; color: white; font-size: 25px; top: 20px; left: 20px}
			div {font-weight: bold}
			#select {top: 575px; left: 60px; border: none; background-color: orange}
		</style>
   
		<img src="http://img110.xooimage.com/files/f/8/8/mapfr-55e6ccf.png"/>
		
		<img id="logo" src="https://www.ojim.fr/wp-content/uploads/2015/06/bfmtv-1.jpg"/>
		
		<select id="select" onchange="InitMap(this.value);">
			<option value="icon" selected>Météo</option>
			<option value="temp">Température (celcius)</option>
			<option value="pressure">Pression atmosphérique (mbar)</option>
			<option value="humidity">Humidité</option>
			<option value="speed">Vitesse du vent</option>
			<option value="name">Villes</option>
		</select>
		
		<div id="thistime"></div>
		
   </body>
   
</html>
Merci ! Super les réponses, les exemples, je pouvais pas espérer mieux Smiley smile ! Je vais garder le lien !
Par contre, et à titre d'info, avec une autre API (que je peux pas donner...) j'ai une erreur : Access to fetch at 'http......' has been blocked by CORS policy...
Et là je n'ai toujours pas trouvé la parade ! Si jamais vous avez des pistes ?
Encore merci Smiley cligne !
Hello,

Alors ça c'est justement ce dont te parlait gcyrillus, souci de CORS Origine !

Mais ... il existe bien sur une parade, on appelle ça un scrapper, en gros on vient "voler" les infos d'une page en modifiant l'en tête CORS.

Et c'est tout à fait possible en full JS aussi !

Je peux te faire un exemple si tu veux Smiley cligne