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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

Q&A

解決済

3回答

4113閲覧

VuejsのComponent内のhrefの値をfetchで取得してDOMを表示したい

mitts

総合スコア17

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

0グッド

0クリップ

投稿2018/06/11 14:01

編集2018/06/11 14:44

前提・実現したいこと

VuejsのComponentを利用してfetchで取得してした配列の数分だけ並べて表示したい
またfetchで取得した配列内のURLに応じてhrefを変更したい

backeendはNode+expressで実装しようとして居ます
fetch で特定のURLでGETした場合 Backendで特定のディレクトリをreadしてファイル名を取得してfrontend に返そうと考えて居ます。

何も表示されない状況です 誤っている箇所を教えていただきたいです

確認したこと

chromeの開発者ビューのデバッグ実行を実施
以下のjson.fileListに目的の文字列(URL)がArrayで格納されていることを確認した

this.imageList = json.fileList;

発生しているエラー

vue.js:597 [Vue warn]: data functions should return an object:
https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function

vue.js:597 [Vue warn]: Property or method "list" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

該当のソースコード

javascript

1var express = require('express'); 2var app = express(); 3var config = require('./config'); 4var fs = require('fs'); 5 6app.get('/',function(req,res){ 7 res.sendfile(__dirname + '/index.html'); 8}); 9 10app.get('/:id',function(req,res){ 11 res.sendfile(__dirname + '/' + req.params.id); 12}); 13 14app.get('/imageList/:id',function(req,res){ 15 var dirName = req.params.id; 16 fs.readdir(__dirname + '/images/' + dirName,function(err,files){ 17 if(err) throw err; 18 var fileList = files.filter(function(file){ 19 return /.*.(jpg|png)$/.test(file); //絞り込み 20 }); 21 var fileListExt = []; 22 fileList.forEach(file => { 23 fileListExt.push('/images/' + dirName+ '/' + file); 24 }); 25 res.json({fileList : fileListExt}); 26 }); 27}); 28 29app.use('/css', express.static('css')); 30app.use('/images', express.static('images')); 31app.use('/js', express.static('js')); 32app.use('/fonts', express.static('fonts')); 33 34app.listen(config.port);

HTML

1<!DOCTYPE HTML> 2<!-- 3 Aesthetic by gettemplates.co 4 Twitter: http://twitter.com/gettemplateco 5 URL: http://gettemplates.co 6--> 7<html> 8 9<head> 10 <meta charset="utf-8"> 11 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 12 13 <!-- Animate.css --> 14 <link rel="stylesheet" href="css/animate.css"> 15 <!-- Icomoon Icon Fonts--> 16 <link rel="stylesheet" href="css/icomoon.css"> 17 <!-- Bootstrap --> 18 <link rel="stylesheet" href="css/bootstrap.css"> 19 <!-- Theme style --> 20 <link rel="stylesheet" href="css/style.css"> 21 22 <!-- Magnific Popup --> 23 <link rel="stylesheet" href="css/magnific-popup.css"> 24 25 <!-- Modernizr JS --> 26 <script src="js/modernizr-2.6.2.min.js"></script> 27 <!-- FOR IE9 below --> 28 <!--[if lt IE 9]> 29 <script src="js/respond.min.js"></script> 30 <![endif]--> 31 32</head> 33 34<body> 35 36 <div class="container-fluid" id="fh5co-image-grid"> 37 <div class="grid" id="image-area"> 38 <div class="grid-sizer"></div> 39 <image-component 40 v-for="elm in list" 41 v-bind:elm = "elm" 42 v-bind:key="elm.key" 43 v-bind:href="elm.value" 44 v-bind:src="elm.value"> 45 </image-component> 46 </div> 47 </div> 48 49 <!-- jQuery --> 50 <script src="js/jquery.min.js"></script> 51 52 <!-- Vue JS --> 53 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 54 <!-- MAIN JS --> 55 <script src="js/main.js"></script> 56 57 <script> 58 var imageList; 59 document.addEventListener('DOMContentLoaded', function () { 60 fetch('/imageList/kyoto').then(function (response) { 61 return response.json(); 62 }).then(function (json) { 63 this.imageList = json.fileList; 64 }); 65 }); 66 Vue.component('image-component', { 67 props: ['elm'], 68 // template : '<li>{{elm}}</li>' 69 template: '<div class="grid-item item animate-box" data-animate-effect="fadeIn">\ 70 <a href="elm.value" class="image-popup" title="Name of photo or title here">\ 71 <div class="img-wrap">\ 72 <img src="elm.value" alt="" class="img-responsive">\ 73 </div>\ 74 <div class="text-wrap">\ 75 <div class="text-inner popup">\ 76 <div>\ 77 <h2>Name of photo or title here</h2>\ 78 </div>\ 79 </div>\ 80 </div>\ 81 </a>\ 82 </div>' 83 }) 84 85 const image = new Vue({ 86 el: '#image-area', 87 data: imageList 88 }) 89 </script> 90</body> 91 92</html>

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

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

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

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

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

karamarimo

2018/06/11 14:26

まずエラーが出ていないかということと、fetch が成功しているか確認してください。
guest

回答3

0

thisのはまりパターンですね。

js

1 var imageList; 2 document.addEventListener('DOMContentLoaded', function () { 3 fetch('/imageList/kyoto').then(function (response) { 4 return response.json(); 5 }).then(function (json) { 6 // ここで this.imagelist は 上記の var imagelistを指していません。 7 this.imageList = json.fileList; 8 // このようにして確認してみましょう 9 console.log(imageList); // undefined つまりグローバルのimageList 10 console.log(this.imageList); // この関数内で新たに定義された imageList 11 }); 12 });

投稿2018/06/11 15:45

euledge

総合スコア2404

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

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

0

ベストアンサー

まず v-bind:key="elm.key" ですが elm は文字列なので key なんていうプロパティは存在しません。
同様に elm.value も存在しないので下記のように書き換え。

html

1<image-component 2 v-for="(elm, index) in imageList" 3 v-bind:elm="elm" 4 v-bind:key="index"> 5</image-component>

次に image-component のテンプレートですが、href="elm.href" などが記述されてますが v-bind 付け忘れてますので、付けます。src="elm.src"も同様。

javascript

1Vue.component('image-component', { 2 props: ['elm'], 3 template: '<div class="grid-item item animate-box" data-animate-effect="fadeIn">\ 4 <a v-bind:href="elm" class="image-popup" title="Name of photo or title here">\ 5 <div class="img-wrap">\ 6 <img v-bind:src="elm" alt="" class="img-responsive">\ 7 </div>\ 8 <div class="text-wrap">\ 9 <div class="text-inner popup">\ 10 <div>\ 11 <h2>Name of photo or title here</h2>\ 12 </div>\ 13 </div>\ 14 </div>\ 15 </a>\ 16 </div>' 17})

最後にデータのフェッチとコンポーネントのマウントですが合体させましょう。
あと、エラーが出てるので分かると思いますが data プロパティは関数にして、戻り値をオブジェクトにしてやりましょう。

javascript

1const image = new Vue({ 2 el: '#image-area', 3 data: function () { 4 return { 5 imageList: [] 6 }; 7 }, 8 created: function () { 9 fetch('/imageList/kyoto').then(function (response) { 10 return response.json(); 11 }).then((function (json) { 12 this.imageList = json.fileList; 13 }).bind(this)); 14 } 15})

投稿2018/06/11 15:43

編集2018/06/11 16:00
yhg

総合スコア2161

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

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

euledge

2018/06/11 15:50

data をオブジェクトでなく関数でというのは、コンポーネントの場合必要なのは理解していますが、メインのインスタンスでも必要でしょうか?
euledge

2018/06/11 15:56

fetch('/imageList/kyoto').then(function (response) { return response.json(); }).then(function (json) { this.imageList = json.fileList; }); ですが、 this.imageList は dataプロパティの値を示さないのでアロー関数で fetch('/imageList/kyoto').then(function (response) { return response.json(); }).then( (json) => { this.imageList = json.fileList; }); としたほうが良いと思います。
yhg

2018/06/11 15:57

コンポーネントを使い回さないので要らないといえば要らないんですが、WARN 出て鬱陶しいですね。理由があってあえてオブジェクトにするとかでなければ、無難にベストプラクティスに従ったほうが良いのではないでしょうか。
yhg

2018/06/11 15:58

あ、ほんとですね。ご指摘ありがとうございます。コンパイルしないみたいなので、`Function.prototype.bind` で束縛したほうが良さそうですね
euledge

2018/06/11 16:01

>yhgさん 束縛の件そうですね、そうでした scriptタグの中でしたね。
euledge

2018/06/11 16:04

>yhgさん dataのwarningの件、jsfiddleで確認してたらワーニングでなかったので気にしてませんでした。 ベストな方向に従うのは同意です。
mitts

2018/06/12 00:37

yhgさん euledgeさん お二方ともコメントいただきありがとうございます! 教えていただいた修正でステップ実行すると狙ったImageが表示されました ただ、ブレークポイントを置かないでリロードするとまた表示されなくなるのはfetchが非同期で行われているからでしょうか
mitts

2018/06/12 03:13

確認したところDOMはきちんと生成されておりクリックすると画像が表示されたので要素はあるけれど描画がうまくされていないようです
mitts

2018/06/12 03:27

Vueでの表示自体はうまくいったのでこのコメントをベストアンサーとさせていただきます お二方本当にありがとうございます
guest

0

v-forで表示ができないという要点のみに注目して回答します。

html

1<div class="grid" id="image-area"> 2 <image-component v-for="elm in list"></image-component> 3</div>

というHTMLに対して vueインスタンスを下記のようにしているのですが、
v-forで使用している list という変数が存在しないので表示されていないのだと思います。

js

1const image = new Vue({ 2 el: '#image-area', 3 data: imageList 4 })

vueインスタンスのところを下記のようにすればよいと思いますよ。

js

1const image = new Vue({ 2 el: '#image-area', 3 data: { 4 list: imageList 5 } 6 })

投稿2018/06/11 14:42

euledge

総合スコア2404

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

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

mitts

2018/06/11 14:48

アドバイスありがとうございます 発生したエラーは教えて頂いた修正でなくなりました ただ依然、componentは表示するされないママです汗
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問