Axios.then().then() running API call twice - how to stop it?

Hello everyone,
I’m trying to complete an MVC-based project, no frameworks - just pure JS. And I seem to have shot myself in the foot somewhere along the way. Google is helpless or sends me to framework-related stuff that solves it in the ‘react/vue way’, which isn’t fit for my situation.

So, the code of the model in question:

		CollectorModel.prototype.getPhotos = function getPhotos(idx,fn){
			const options = {
				headers:{
					<Private keys here>
				}
			};

			let url = `https://api.unsplash.com/collections/${idx}/photos`;

			return axios.get(url,options)
			.then((response) => {
				fn(response.data);		
				return response.data;
			});
		} 

		CollectorModel.prototype.getDetails = async function getDetails(idx2,fn2){
			await collectorModel.getPhotos();
			collectorModel.getPhotos().then((data) => fn2(data[idx2]));
		}

So, what happens here is a first (needed) call is made to the API, then a Promise with data is retrieved. All I want is to get the data from the first function and reuse it in the second one, but it makes another call to undefined index in the process, and drops with an error. I read up on cancellation, but that goes in the .get() part, and I only have .then() here.

There are also view and controller sections, but I really don’t think they’re the issue. My first call (not shown here) runs only once, as expected, and these two are wired up by the same template. It’s something with the way I pass a Promise to the second function, that triggers the request. Repeated collectorModel.getPhotos()? But how do I pass the response without it, then…

Confused, no idea how to proceed with this. Pls help

It appears you are calling getPhotos() twice.

I’m not good with async (yet) but maybe just:
collectorModel.getPhotos().then((data) => fn2(data[idx2])); ?

1 Like

Thank you. Already tried, same stuff.

When I try to call a scheme like that separately, though, it works only once, as intended. Which is weird, and at this point it might not be the model’s issue.
I have an addEventListener with a click event, that gets a div’s ID and sends it down the chain. But still, getDetails() doesn’t have a get() option to make a call with it! It is just supposed to receive a .then() with a Promise from getPhotos() and do stuff with it.
I just don’t know where this extra request is coming from. Going to post the full code now, maybe something’s wrong elsewhere.
If you have the patience to go through it - please do, if not - don’t. I might be asking for too much.

Full code

		//model
		var CollectorModel = function CollectorModel(axios){
			this.axios = axios;
		}

		CollectorModel.prototype.sendCollection = function sendCollection(fn){
			const options = {
				headers:{
					<keys>
				}
			};

			axios.get('https://api.unsplash.com/collections?per_page=20',options)
			.then(function(response) {
				fn(response.data);
			});
		}
		CollectorModel.prototype.getPhotos = function getPhotos(idx,fn){
			const options = {
				headers:{
					<keys>
				}
			};

			let url = `https://api.unsplash.com/collections/${idx}/photos`;

			return axios.get(url,options)
			.then((response) => {
				fn(response.data);		
				return response.data;
			})
		} 

		CollectorModel.prototype.getDetails = async function getDetails(idx2,fn2){
			collectorModel.getPhotos().then((data) => fn2(data[idx2]));
		}

		//view
		var CollectorView = function CollectorView(element1,element2,element3){
			this.element1 = element1;
			this.element2 = element2;
			this.element3 = element3;
		}

		CollectorView.prototype.renderCollections = function renderCollections(viewModel){
			this.element1.innerHTML = viewModel.map(el => `<div>
				<h3>${el.title}</h3>
				<h4>${el.description}</h4>
				<h5>${el.total_photos}</h5>
				<a href="#collections__photos">
					<p class="circle" id="${el.id}"></p>
				</a>
			</div>`)
			.join("");
		}

		CollectorView.prototype.renderPhotos = function renderPhotos(viewModel){
			this.element2.innerHTML = viewModel.map(el => `<div>
				${el.description?el.description:el.alt_description}
				<a href="#photos__details">
					<p class="circle" id="${viewModel.indexOf(el)}">
				</a>
			</div>`)
			.join("");
		} 

		CollectorView.prototype.renderDetails = function renderDetails(viewModel){
			this.element3.innerHTML = `<div>${viewModel.id}${viewModel.created_at}${viewModel.description?el.description:el.alt_description}</div>`
		}

		//controller
		var CollectorController = function CollectorController(collectorView,collectorModel){
			this.collectorView = collectorView;
			this.collectorModel = collectorModel;
		}

		CollectorController.prototype.getCollection = function getCollection(){
			this.collectorModel.sendCollection(this.showCollection.bind(this));
		}
		CollectorController.prototype.showCollection = function showCollection(collectorModelData){
			this.collectorView.renderCollections(collectorModelData);
		}

		CollectorController.prototype.onClickGetPhotos = function onClickGetPhotos(e){
			return new Promise( resolve => {
				let scope = document.getElementById('collections');
				scope.addEventListener('click', e =>
					(!e.target.id || e.target.id === 'collections') ? null : resolve(e.target.id)
				)		
			});		
		} 
		CollectorController.prototype.sendId = async function sendId(){
			let idx = await controller.onClickGetPhotos();
			this.collectorModel.getPhotos(idx, this.showPhotos.bind(this));
		}
		CollectorController.prototype.showPhotos = function showPhotos(collectorModelData){
			this.collectorView.renderPhotos(collectorModelData);
		} 

		CollectorController.prototype.onClickGetDetails = function onClickGetDetails(e){
			return new Promise( resolve => {
				let scope = document.getElementById('collections__photos');
				scope.addEventListener('click', e =>
					(!e.target.id || e.target.id === 'collections') ? null : resolve(e.target.id)
				)		
			});		
		} 
		CollectorController.prototype.sendDetailsId = async function sendDetailsId(){
			let idx = await controller.onClickGetDetails();
			this.collectorModel.getDetails(idx, this.showDetails.bind(this));
		}
		CollectorController.prototype.showDetails = function showDetails(collectorModelData){
			this.collectorView.renderDetails(collectorModelData);
		}

		var collectorModel = new CollectorModel(axios);

		var targetElement1 = document.getElementById('collections');
		var collectorView = new CollectorView(targetElement1);
		var controller = new CollectorController(collectorView, collectorModel);
		controller.getCollection();

		var targetElement2 = document.getElementById('collections__photos');
		var collectorView = new CollectorView(undefined, targetElement2);
		var controller = new CollectorController(collectorView, collectorModel);
		controller.sendId();

		var targetElement3 = document.getElementById('photos__details');
		var collectorView = new CollectorView(undefined, undefined, targetElement3);
		var controller = new CollectorController(collectorView, collectorModel);
		controller.sendDetailsId();