locked
orderByMusicProperties produces different results?

    Question

  • Hello guys.

    I'm playing with files and I'm following along this session http://channel9.msdn.com/Events/BUILD/BUILD2011/PLAT-891T

    NOw, I've got the following code for grouping by album and listing the mp3 files associated with each album:

    musicLibrary.createFolderQueryWithOptions(opcoes).getFoldersAsync()
                .then(function (items) {
                    items.forEach(function (item) {
                        var div = document.createElement("div");
                        div.innerHTML = item.name;
                        var img = document.createElement("img");
                        img.alt = item.name;
                        item.getThumbnailAsync(Windows.Storage.FileProperties.ThumbnailMode.musicView, 150,
                            Windows.Storage.FileProperties.ThumbnailOptions.resizeThumbnail)
                            .done(function (thumbnail) {
                                img.src = thumbnail ? URL.createObjectURL(thumbnail) : "images/logo.png";
                            });
                        var itemInfo = document.createElement("div");
                        itemInfo.appendChild(img);
                        itemInfo.appendChild(div);
                        itemInfo.addEventListener("click", function () {
                            divMusicas.innerHTML = "";
                            var ordem = Windows.Storage.Search.CommonFileQuery.orderByMusicProperties;
                            var tipos = [".mp3"];
                            var opcoes = new Windows.Storage.Search.QueryOptions(ordem, tipos);
                            item.createFileQueryWithOptions(opcoes)
                                .getFilesAsync().then(function (musicas) {
                                    musicas.forEach(function (musica) {
                                        var musicaDiv = document.createElement("div");
                                        musica.properties.getMusicPropertiesAsync()
                                              .then(function (propriedades) {
                                                  var texto = propriedades.trackNumber + "-" + propriedades.title +
                                                      " (" + new Date(propriedades.duration).toLocaleTimeString() + ")";
                                                  musicaDiv.innerHTML = texto;
                                                  divMusicas.appendChild(musicaDiv);
                                              });


                                    });
                                });
                        });
                        lista.appendChild(itemInfo);
                    });
                });
        }

    The problem I'm having is that clicking over the same item several times ends up producing different sorts. Here are two images that show what happen after I click once and twice over the same album. Any clues on what's going on?


    Luis Abreu

    Wednesday, March 21, 2012 10:04 PM

Answers

  • Another issue might be that you're asynchronously getting properties in a forEach loop. The forEach does not guarantee order, so depending on how fast the different async operations return, you may be creating the DOM out of order. Here's a pattern that would guarantee ordering:

    item.createFileQueryWithOptions(opcoes)
        .getFilesAsync().then(function (musicas) {
            // Add all property retrieval promises to an array of promises
            var promises = musicas.map(function (musica) {
                return musica.properties.getMusicPropertiesAsync();
            });
            // Join all promises and wait for all to complete before creating the DOM
            WinJS.Promise.join(promises).then(function (propriedades) {
                for (var i in propriedades) {
                    var musicaDiv = document.createElement("div");
                    var texto = propriedades[i].trackNumber + "-" + propriedades[i].title +
                        " (" + new Date(propriedades[i].duration).toLocaleTimeString() + ")";
                    musicaDiv.innerHTML = texto;
                    divMusicas.appendChild(musicaDiv);
                }
            });
        });

    Can you try this and let us know if it works?
    Tuesday, March 27, 2012 10:11 PM

All replies

  • The action is async, the second click may happen before completing the first click action. And please use WinJS.Utilities.empty() method to empty the divMusicas element.

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    Thursday, March 22, 2012 7:59 AM
  • Hello Bob.

    Regarding your observations, I'm sure that it didnt' happen in my case. I never clicked twice on the same item before seeing the list of musics. And the first image shows the result after running the app and clicking for the first time over.

    I'll change the way the cleaning is done and I'll report back if there's any change.


    Luis Abreu

    Thursday, March 22, 2012 12:33 PM
  • Another issue might be that you're asynchronously getting properties in a forEach loop. The forEach does not guarantee order, so depending on how fast the different async operations return, you may be creating the DOM out of order. Here's a pattern that would guarantee ordering:

    item.createFileQueryWithOptions(opcoes)
        .getFilesAsync().then(function (musicas) {
            // Add all property retrieval promises to an array of promises
            var promises = musicas.map(function (musica) {
                return musica.properties.getMusicPropertiesAsync();
            });
            // Join all promises and wait for all to complete before creating the DOM
            WinJS.Promise.join(promises).then(function (propriedades) {
                for (var i in propriedades) {
                    var musicaDiv = document.createElement("div");
                    var texto = propriedades[i].trackNumber + "-" + propriedades[i].title +
                        " (" + new Date(propriedades[i].duration).toLocaleTimeString() + ")";
                    musicaDiv.innerHTML = texto;
                    divMusicas.appendChild(musicaDiv);
                }
            });
        });

    Can you try this and let us know if it works?
    Tuesday, March 27, 2012 10:11 PM
  • Ah, damn...this makes complete sense...

    I'll give it a shot later, when I get home.

    Thanks Marc.


    Luis Abreu

    Wednesday, March 28, 2012 12:00 PM
  • Yes, that was my error :)

    thanks.


    Luis Abreu

    Wednesday, March 28, 2012 6:44 PM