質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
mBaaS

mBaaSとはモバイルアプリケーションでの利用に特化したBaaSです。スマートフォン向けのWebアプリケーションが必要とするサーバ側の様々な機能をインターネットを通じてサービスとして提供しています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Monaca

「Monaca」はiOS、Android、Windows向けのアプリ開発に対応した、Cordovaベースのモバイルアプリ開発プラットフォームです。HTML5、JavaScriptといったWeb標準技術を用いてモバイルアプリ開発を行うことができます。

Q&A

解決済

1回答

1961閲覧

【Monaca×ニフクラmbaas】ファイルストアにある画像を順番通りにリスト表示させたい

yusuke22

総合スコア8

mBaaS

mBaaSとはモバイルアプリケーションでの利用に特化したBaaSです。スマートフォン向けのWebアプリケーションが必要とするサーバ側の様々な機能をインターネットを通じてサービスとして提供しています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Monaca

「Monaca」はiOS、Android、Windows向けのアプリ開発に対応した、Cordovaベースのモバイルアプリ開発プラットフォームです。HTML5、JavaScriptといったWeb標準技術を用いてモバイルアプリ開発を行うことができます。

0グッド

0クリップ

投稿2020/01/07 07:11

前提・実現したいこと

ニフクラのファイルストアに保存している画像を新しい順でリスト形式に表示したいのですが、表示させるたびに順番が変わってしまいます。
データストアのオブジェクトを検索し該当したファイル名(ファイルストアの画像と同じ)でファイルストアに保存されている画像を取得、リスト形式に表示させようとしています。
その際にリストをタップするとイベントが発生するようにしています。

例)

  • 画像1: イベント1
  • 画像2: イベント2
  • 画像3: イベント3

現在、画像をリスト形式で表示させることはできたのですが、表示させるたびに順番が変わってしまいます。
またリストごとにイベントを追加できたのですが画像と紐付いません。
画像を順番通りに表示させる方法はないでしょうか。
また原因などを探る方法をご教授下さい。

該当のソースコード

javascript

1function select(category) { 2 myNavigator.pushPage('display.html');  //画面遷移 3 var LaundryData = ncmb.DataStore("LaundryData"); 4 var currentUser = ncmb.User.getCurrentUser(); 5 LaundryData.equalTo("owner", currentUser.get("userName"))  //現在ログインしているユーザ、あてはまるカテゴリで検索 6 .equalTo("categoryData", category) 7 .order("laundryName") 8 .fetchAll() 9 .then(function(results) { 10 var markData1 = []; 11 console.log(category + ":" + results.length); 12 for(var i = 0; i < results.length; i++) { 13 var reader = new FileReader(); 14 reader.onload = (function(e) { 15 var dataUrl = reader.result; 16 var display = document.getElementById('display');  //HTMLにあるons-listタグを取得 17 var list = document.createElement('ons-list-item'); 18 list.setAttribute("modifier", "chevron"); 19 list.setAttribute("tappable", ""); 20 var img = document.createElement('img'); 21 img.setAttribute("wisth", "100"); 22 img.setAttribute("height", "100"); 23 display.appendChild(list).appendChild(img); 24 var listItems = display.children; 25 for(var i = 0; i < listItems.length; i++) {  //生成した各リストにイベントを追加 26 listItems[i].firstChild.src = dataUrl; 27 listItems[i].onclick = function(i) { 28 var mark = markData1[i]; 29 return function() { 30 result(mark); 31 console.log(mark); 32 } 33 }(i) 34 } 35 }); 36 var object = results[i]; 37 var imageName = object.laundryName; 38 markData1[i] = object.markData1; 39 console.log(imageName); 40 ncmb.File.download(imageName, "blob")  //ファイルストアからダウンロード 41 .then(function(blob) { 42 reader.readAsDataURL(blob); 43 }) 44 .catch(function(error) { 45 console.log(error); 46 }); 47 } 48 }) 49 .catch(function(error) { 50 console.log(error); 51 });

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

実行する度に順番が異なる理由は、恐らくですがJavaScriptの非同期処理に関連しているのかなと。

下記の ここ の時点では並び順は希望した通りになっているならば、非同期処理のせいです。

js

1for(var i = 0; i < results.length; i++) { 2 // ここ 3}

非同期処理は ncmb.File.download になります。この処理がforループ中で繰り返し呼ばれるので、ダウンロードできた順に reader.readAsDataURL が呼ばれています。前のダウンロードを追い越して render 変数が上書きされて呼ばれている可能性があります。

解決策としては async/await を使って非同期処理を止める、またはループ処理を別な関数にする手があります。別な関数にすれば、変数の空間が分かれるので、上書きを防止できます。

例えばこんな感じです(ちゃんと動くかは実行していないので保証できません)。ただし、この方法では並び順(ダウンロード完了順)は保証できません。

js

1function select(category) { 2 myNavigator.pushPage('display.html');  //画面遷移 3 var LaundryData = ncmb.DataStore("LaundryData"); 4 var currentUser = ncmb.User.getCurrentUser(); 5 LaundryData.equalTo("owner", currentUser.get("userName"))  //現在ログインしているユーザ、あてはまるカテゴリで検索 6 .equalTo("categoryData", category) 7 .order("laundryName") 8 .fetchAll() 9 .then(function(results) { 10 var markData1 = []; 11 console.log(category + ":" + results.length); 12 for(var i = 0; i < results.length; i++) { 13 // 関数化 14 downloadObject(results[i]); 15 } 16 }) 17 .catch(function(error) { 18 console.log(error); 19 }); 20} 21 22function downloadObject(object) { 23 var reader = new FileReader(); 24 reader.onload = (function(e) { 25 var dataUrl = reader.result; 26 var display = document.getElementById('display');  //HTMLにあるons-listタグを取得 27 var list = document.createElement('ons-list-item'); 28 list.setAttribute("modifier", "chevron"); 29 list.setAttribute("tappable", ""); 30 var img = document.createElement('img'); 31 img.setAttribute("wisth", "100"); 32 img.setAttribute("height", "100"); 33 display.appendChild(list).appendChild(img); 34 var listItems = display.children; 35 for(var i = 0; i < listItems.length; i++) {  //生成した各リストにイベントを追加 36 listItems[i].firstChild.src = dataUrl; 37 listItems[i].onclick = function(i) { 38 var mark = markData1[i]; 39 return function() { 40 result(mark); 41 console.log(mark); 42 } 43 }(i) 44 } 45 }); 46 var object = results[i]; 47 var imageName = object.laundryName; 48 markData1[i] = object.markData1; 49 console.log(imageName); 50 ncmb.File.download(imageName, "blob")  //ファイルストアからダウンロード 51 .then(function(blob) { 52 reader.readAsDataURL(blob); 53 }) 54 .catch(function(error) { 55 console.log(error); 56 }); 57}

async/awaitに変更する場合は呼び出し元もasync関数じゃないといけない、また await select で呼び出す形になるので注意してください。例えばこんな感じです。

js

1// asyncに変更 2async function select(category) { 3 myNavigator.pushPage('display.html');  //画面遷移 4 var LaundryData = ncmb.DataStore("LaundryData"); 5 var currentUser = ncmb.User.getCurrentUser(); 6 try { 7 // awaitに変更 8 var results = await LaundryData.equalTo("owner", currentUser.get("userName"))  //現在ログインしているユーザ、あてはまるカテゴリで検索 9 .equalTo("categoryData", category) 10 .order("laundryName") 11 .fetchAll(); 12 var markData1 = []; 13 console.log(category + ":" + results.length); 14 for(var i = 0; i < results.length; i++) { 15 var reader = new FileReader(); 16 reader.onload = (function(e) { 17 var dataUrl = reader.result; 18 var display = document.getElementById('display');  //HTMLにあるons-listタグを取得 19 var list = document.createElement('ons-list-item'); 20 list.setAttribute("modifier", "chevron"); 21 list.setAttribute("tappable", ""); 22 var img = document.createElement('img'); 23 img.setAttribute("wisth", "100"); 24 img.setAttribute("height", "100"); 25 display.appendChild(list).appendChild(img); 26 var listItems = display.children; 27 for(var i = 0; i < listItems.length; i++) {  //生成した各リストにイベントを追加 28 listItems[i].firstChild.src = dataUrl; 29 listItems[i].onclick = function(i) { 30 var mark = markData1[i]; 31 return function() { 32 result(mark); 33 console.log(mark); 34 } 35 }(i) 36 } 37 }); 38 var object = results[i]; 39 var imageName = object.laundryName; 40 markData1[i] = object.markData1; 41 try { 42 // awaitに変更 43 var blob = await ncmb.File.download(imageName, "blob")  //ファイルストアからダウンロード 44 reader.readAsDataURL(blob); 45 } catch (error) { 46 console.log(error); 47 } 48 } 49 } catch (error) { 50 console.log(error); 51 } 52}

async/awaitはforループ中のダウンロード完了を待ってしまうので、非同期処理で次々とダウンロードが行われるのに比べると時間がかかってしまいます。ただし並び順は保証できます。

投稿2020/01/07 08:42

編集2020/01/07 08:45
moongift

総合スコア250

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yusuke22

2020/01/07 14:42

回答ありがとうございます。 イベントと画像の情報は一致させたいので、2つ目のコードを実行しましたが1番下のリストにのみ画像が表示されてしまいました。 すべてのそれぞれのリストに画像を表示したいのですが、改善点ございますでしょうか。
otak-lab

2020/01/08 01:43

forループ内のvar reader = new FileReader();において、readerが何度も書き替えられるので、結果的に最後の画像のみ表示されるのではないでしょうか。
yusuke22

2020/01/08 14:18

回答ありがとうございます。 for文の外に宣言したところ画像表示できました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問