-1
votes

Javascript - .push () plusieurs objets de la boucle for dans un tableau multidimensionnel

J'exécute une fonction qui doit pousser 16 objets dans la position i d'un tableau multidimensionnel. Je suis capable de pousser toutes les données dans var = videoData utilisant videoData.push(videoItem) mais je dois me retrouver avec un tableau multidimensionnel où chaque tableau imbriqué contient 16 objets.

var videoData = [[vid01, vid02....vid16], [vid01, vid02... vid16]]

Je m'attends à finir avec ...

//variables
videoData       = [],
countries       = ["GB", "ES", "PT", "VN", "ID"],
tags            = ["?tags=english", "?tags=spanish", "?tags=portugues", "?tags=vietnam", "?tags=indonesia"]

//function
function runTask(){
    for(var i = 0; i < countries.length; i++){
        axios({
            method: "get",
            url: api_url + tags[i],
            headers: {
                "Content-Type": "application/json"
            },
        })
        .then(function(response) {
            var sixteenVideos = response.data
            for(var x = 0; x < 16; x++){
                var videoItem = {
                    "keys": {
                        video: "vid" + [x+1]
                    },
                    "values": {
                        url: sixteenVideos[x].slug,
                        thumb: sixteenVideos[x].image,
                        title: sixteenVideos[x].title,
                        desc: sixteenVideos[x].description
                    }
                }
                videoData[i].push([videoItem]);   
            }
            console.log(videoData);
        }).catch(function(error) {
            console.log(error);
        });
    }
}


5 commentaires

Quelle est la sortie de courant? Est-ce quelque chose comme [vid01,[vid01...]...] ?


Non, c'est des erreurs pour le moment. Il montre TypeError: Cannot read property 'push' of undefined


Cela signifie que quel que soit le système videoitem , il n'est pas défini. Êtes-vous sûr de recevoir correctement les données? Qu'est-ce que vous console.log(response); ? Vous poussez également un tableau d'objets comme ça. .push(videoItem); simplement .push(videoItem); .


La réponse ci-dessous d'Alex Gray fonctionne :)


n'oubliez pas d'utiliser const , let ou var lors de la déclaration de variables


4 Réponses :


0
votes

Vous souhaitez utiliser une boucle similaire à celle-ci pour créer votre tableau multidimensionnel

function runTask() {
  var videoData = [];
  for (var i = 0; i < 6; i++) {
    var country = "Country -" + i;
    var countryArray = [];
    for (var x = 0; x < 16; x++) {
      var videoItem = country + ", Video -" + x;
      countryArray.push(videoItem);
    }

    videoData.push(countryArray);
  }
}


0 commentaires

1
votes

For boucle For fonctionne de manière synchrone, lors de l'exécution d'opérations asynchrones dans la boucle for , au moment où les promesses sont résolues for boucle terminée, son exécution. Ainsi, la valeur de i aura la valeur de la dernière itération de boucle dans chaque promesse résolue.

Je ne pense pas que la boucle for soit vraiment nécessaire ici, il peut être plus simple de créer une fonction qui prend une balise et renvoie une promesse qui se résout en un tableau de 16 éléments, cela peut ressembler à ceci:

var videoData = [];
var countries = ["GB", "ES", "PT", "VN", "ID"];
var tags      = ["?tags=english", "?tags=spanish", "?tags=portugues", "?tags=vietnam", "?tags=indonesia"];

var tasks = tags.map(runTask);
Promise.all(tasks).then(result => {
  console.log(result)
});

function runTask(tag) {
  return axios({
    method: "get",
    url: api_url + tag,
    headers: {
      "Content-Type": "application/json"
    },
  }).then((response) => 
    response.data
      .slice(0, 16)
      .map((video, index) => ({
        "keys": {
          video: "vid" + [index + 1]
        },
        "values": {
          url: video.slug,
          thumb: video.image,
          title: video.title,
          desc: video.description
        } 
      }))
  ).catch(err => {
    console.log(err)
  })
}


0 commentaires

0
votes

Il y a beaucoup de problèmes avec votre code actuel. Je vais partir de zéro dans l'espoir que vous puissiez voir une meilleure façon d'aborder cela. Premièrement, axios a de nombreuses fonctionnalités de bas niveau que vous ne devriez pas vous inquiéter à chaque fois que vous récupérez json. Commencez par quelque chose comme fetchJson -

const apiUrl =
  "https://my.api/"

const requests =
  [ { country: "GB", tags: "?tags=english" }
  , { country: "ES", tags: "?tags=spanish" }
  , { country: "PT", tags: "?tags=portugues" }
  , { country: "VN", tags: "?tags=vietnam" }
  , { country: "ID", tags: "?tags=indonesia" }
  ]

const fetchJson = (url = "") =>
  axios
    ( { method: "get"
      , url
      , headers: { "Content-Type": "application/json" }
      }
    )
    .then(res => res.data)

const fetchVideos = ({ country = "", tag = "" }) =>
  fetchJson(apiUrl + tag)
    .then(apiVideos => apiVideos.map(videoFromApi)) 
    .then(videos => ({ country, videos }))

const videoFromApi =
  ( { slug = ""
    , image = ""
    , title = ""
    , description = ""
    }
  , id = 0
  ) =>
    Object.assign
      ( { keys: { video: `vid${id + 1}` } }
      , { values:
          { url: slug 
          , thumb: image
          , title: title
          , desc: description
          }
        }
      )

// mocks
const axios = async (req = {}) =>
  ({ data: randomVideos(4) })

const randomVideos = (n = 0) =>
  Array.from(Array(n), randomVideo)

const randomVideo = (_, id) =>
  ( { url: `videourl/${id}`
    , image: `images/v${id}.jpg`
    , title: `Video: ${id}`
    , description: `This is video ${1}.`
    }
  )

// run demo
Promise
  .all(requests.map(fetchVideos))
  .then(console.log, console.error)

// [ { country: "GB", videos: [ v1, v2, v3, ... ] }
// , { country: "ES", videos: [ v1, v2, v3, ... ] }
// , { country: "PT", videos: [ v1, v2, v3, ... ] }
// , { country: "VN", videos: [ v1, v2, v3, ... ] }
// , { country: "IN", videos: [ v1, v2, v3, ... ] }
// ]

Maintenant, lorsque nous écrivons fetchVideos , nous pouvons compter sur fetchJson et sauter directement dans ce que nous devons faire avec la réponse analysée -

const requests =
  [ { country: "GB", tags: "?tags=english" }
  , { country: "ES", tags: "?tags=spanish" }
  , { country: "PT", tags: "?tags=portugues" }
  , { country: "VN", tags: "?tags=vietnam" }
  , { country: "ID", tags: "?tags=indonesia" }
  ]

Promise
  .all(requests.map(fetchVideos))   // fetchVideos for each request
  .then(console.log, console.error) // then log the output, or error if incurred

// [ { country: "GB", videos: [ v1, v2, v3, ... ] }
// , { country: "ES", videos: [ v1, v2, v3, ... ] }
// , { country: "PT", videos: [ v1, v2, v3, ... ] }
// , { country: "VN", videos: [ v1, v2, v3, ... ] }
// , { country: "IN", videos: [ v1, v2, v3, ... ] }
// ]

Au lieu de s'appuyer sur des tableaux séparés de countries et de tags , fetchVideo prend une entrée d' objet telle que -

const videoFromApi =
  ( { slug = ""
    , image = ""
    , title = ""
    , description = ""
    }
  , id = 0
  ) =>
    Object.assign
      ( { keys: { video: `vid${id + 1}` } }
      , { values:
          { url: slug 
          , thumb: image
          , title: title
          , desc: description
          }
        }
      )

Et il produira un objet tel que -

// { country: "GB", videos: [ v1, v2, v3, ... ] }

Cela évite d'avoir à utiliser des index bruts pour lier des valeurs entre elles. Et nous avons gardé fetchVideos haut niveau en fonction d'une autre fonction videoFromApi . Cette fonction convertira les données de réponse vidéo de l'API dans la forme souhaitée pour notre application -

fetchVideos({ country: "GB", tag: "?tags=english" })
  .then(console.log, console.error)

Maintenant, pour lier tout cela, nous définissons un tableau de requests et utilisons Promise.all pour fetchVideos des fetchVideos pour chaque requête. NB, cela nous permet de savoir précisément quand toutes les récupérations d'API sont terminées afin que notre programme puisse passer à l'étape suivante -

const apiUrl =
  "https://my.api/"

const fetchVideos = ({ country = "", tag = "" }) =>
  fetchJson(apiUrl + tag)
    .then(apiVideos => apiVideos.map(videoFromApi)) // convert each video
    .then(videos => ({ country, videos })) // build response

Pour voir une démo fonctionnelle, développez l'extrait ci-dessous et exécutez-le. axios a été randomVideos avec randomVideos afin que nous puissions simuler une requête d'API -

const fetchJson = (url = "") =>
  axios
    ( { method: "get"
      , url
      , headers: { "Content-Type": "application/json" }
      }
    )
    .then(res => res.data)


0 commentaires

0
votes

Eh bien, vous ne pouvez pas faire cela "videoData[i].push" car la position sur le tableau n'existe pas. Vous pouvez résoudre ce problème en utilisant un tableau auxiliaire comme celui-ci:

for(var x = 0; x < 16; x++){
            var videoItem = {
                "keys": {
                    video: "vid" + [x+1]
                },
                "values": {
                    url: sixteenVideos[x].slug,
                    thumb: sixteenVideos[x].image,
                    title: sixteenVideos[x].title,
                    desc: sixteenVideos[x].description
                }
            }
            videoDataAux.push([videoItem]);   
        }
videoData[i]=videoDataAux

et que:

videoData = []
videoDataAux = []


0 commentaires