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

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

ただいまの
回答率

90.11%

vue.js tableの一マス文だけ色を変えるには??

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,536

kazoogon

score 269

只今Laravel5.5 vue.jsを使用し予定表のようなものをtableを使って作成しております。
<期待値>どこかをクリックするとそのマス目だけ色が変わる(もう一度clickすると、色は戻る)
イメージ説明

「html側、table.tbodyのコード」

<tobody>
    @foreach ($master_reservation_times as $master_reservation_time)
        <tr>
            <th scope="row">{{ $master_reservation_time->time }}</th>
            <td scope="row" class="hoge" v-for='(item,index) in items' v-bind:class='{ active: isActive }' v-on:click='empty(index)'>@{{item.date}}</td>
        </tr>
    @endforeach
</tobody>

「js側」

const demo = new Vue({
    el: '#demo2',
    data: {
        isActive: false,
        items: [
            {date: '1', message: 'nie można' },
            {date: '2', message: 'nie można' },
            {date: '3', message: 'nie można' },
            {date: '4', message: 'nie można' },
            {date: '5', message: 'nie można' },
            {date: '6', message: 'nie można' },
            {date: '7', message: 'nie można' },
        ]
    },
    methods:{
        empty:function(index){
            return this.isActive = true;  //ここでどのようにindexをもたせればよいか??
        }
    }
});

ここまではできるのですが、indexをどうfunctionの中で持たせれば良いかわからずに困っております。(現状ではマス目が全部変わり、もう一度clickしても元には戻りません)
またv-on:click='isActive=!isActive'とすればclick二回目で元に戻りますが、これだとindexの値を渡ないというか、methodが使えない(?)のでマス目を指定してなにか変化させることができません。

よろしくお願いいたします。

回答を受けての追加

回答ありがとうございますeuledgeさん。
若干表示側のコードをいじりましたが、現状は1マスクリックするとこのように縦1列全ての色が変わります。
イメージ説明
「試してみたこと」
下記コードのようにvue.jsで横の時間の情報を持たせ、1マスごとに「1.1」「1.2」と情報を持たす

const demo = new Vue({
el: '#demo2',
data: {
    rows :[
        {time: '1', message: "9:00-10:00"},
        {time: '2', message: "10:00-11:00"},
        {time: '3', message: "11:00-12:00" },
        {time: '4', message: "12:00-13:00" },
        {time: '5', message: "13:00-14:00" },
        {time: '6', message: "14:00-15:00" },
        {time: '7', message: "15:00-16:00" },
        {time: '8', message: "16:00-17:00" },
        {time: '9', message: "18:00-19:00" },
        {time: '10', message: "19:00-20:00" },
        {time: '11', message: "20:00-21:00" },
    ],
    columns: [
        {date: '1', message: 'nie można' ,isActive: false},
        {date: '2', message: 'nie można' ,isActive: false},
        {date: '3', message: 'nie można' ,isActive: false},
        {date: '4', message: 'nie można' ,isActive: false},
        {date: '5', message: 'nie można' ,isActive: false},
        {date: '6', message: 'nie można' ,isActive: false},
        {date: '7', message: 'nie można' ,isActive: false},
    ]
},


↓表示側のコードはこのように変更。
問題点はv-on:click='empty(index)'部分にてcolumn.dateとrow.timeの情報を引数で渡し、その部分だけ色が変わるようにしようと思っていますが、うまいこといかずに困っております。

<tr v-for="row in rows">
    <th scope="row">@{{ row.message }}</th>
    <td scope="row" class="hoge" v-for='(column,index) in columns' v-bind:class='{ active: column.isActive }' v-on:click='empty(index)'>@{{ column.date }}:@{{ row.time }}</td>
</tr>

よろしくお願いいたします。

回答を受けての追加②

回答ありがとうございますeuledgeさん。

v-for='(row,index) in rows'

についてなんですが、これは

rows :[
        {time: '1', message: "9:00-10:00", index: 1},
        {time: '2', message: "10:00-11:00", index: 2},
        {time: '3', message: "11:00-12:00", index: 3},
        {time: '4', message: "12:00-13:00", index: 4},
        {time: '5', message: "13:00-14:00", index: 5},
        {time: '6', message: "14:00-15:00", index: 5},
        {time: '7', message: "15:00-16:00", index: 6},
        {time: '8', message: "16:00-17:00", index: 7},
        {time: '9', message: "18:00-19:00", index: 8},
        {time: '10', message: "19:00-20:00", index: 9},
        {time: '11', message: "20:00-21:00", index: 10 }
    ],


と、indexプロパティが追加されている(?)イメージだと思っております。ですので以下のように変更致しました。

「html部分」

<tr v-for="(row,index) in rows">
    <th scope="row">@{{ row.message }}</th>
    <td scope="row" class="hoge" v-for='(column,index) in row.columns' v-bind:class='{ active: column.isActive }' v-on:click='empty(row.index,column.index)'>@{{ column.date }}:@{{ row.time }}</td>
</tr>


「js method部分」

methods:{
    empty:function(row,column){
        return this.rows[row].columns[column].isActive = ! this.rows[row].columns[column].isActive;
    }
}


とそれぞれ変更しましたが、Uncaught TypeError: Cannot read property 'columns' of undefinedとエラーが出ます。rowsの中にcolumnsというpropertyはあるのに。。。?となっております。
度々申し訳ありませんが、よろしくお願いいたします。

回答を受けての追加③

回答ありがとうございますeuledgeさん。
ご指摘の通りコードを修正すると期待値通り動作しました。
しかしコードが長いので変数にデータをいれて使おうと思いこのようにしました(ここではいただいたhttps://jsfiddle.net/3gozgbj9/42/を使用します、そちらの方が分かりやすいと思いますので)

var date = [
                {date: '1', message: 'nie można', isActive: true },
                {date: '2', message: 'nie można', isActive: true },
                {date: '3', message: 'nie można', isActive: true },
                {date: '4', message: 'nie można', isActive: true },
                {date: '5', message: 'nie można', isActive: true },
                {date: '6', message: 'nie można', isActive: true },
                {date: '7', message: 'nie można', isActive: true },
            ]
const demo = new Vue({
    el: '#demo2',
    data: {
        rows: [
          {name: 'item1',
            columns: date
          },
          {name: 'item2',
            columns: date
          }
        ],
    },
    methods:{
        empty:function(rowIndex, colIndex){
          this.rows[rowIndex].columns[colIndex].isActive = !this.rows[rowIndex].columns[colIndex].isActive;
        }
    }
});


このようにすると縦列全部の色が変わってしまいます。変数を使うだけでこのようになる理由が不明で困っております。。
長々申し訳ございませんが、よろしくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • gouf

    2018/04/09 15:27

    「return this.isActive = true」を「return this.isActive = !this.isActive」に書き換えた場合に動作に変化は見られますか?

    キャンセル

  • kazoogon

    2018/04/09 15:38

    回答ありがとうございます。 ご指摘の通り修正しましたところ、click二回目で色は元に戻りました、ありがとうございます。 後はclickしたマス目の部分だけの色が変化すればよいですが、、indexをどう扱えばいいのかわからなくて困っております

    キャンセル

  • gouf

    2018/04/09 21:33

    「method が使えない」とはどのような意味でしょうか、たとえば 次のような構造に書き換えれば解決しますか?: http://gouf.hatenablog.com/entry/2018/04/09/011338

    キャンセル

回答 4

checkベストアンサー

0

同じ変数 dateを使用していますが、この場合両方とも同じものをさしています(var date で宣言したもの) これはjavascriptの言語的仕様です。したがって片方の値を変えたつもりでも両方の値が変わったようになります。

  rows: [
          {name: 'item1',
            columns: date
          },
          {name: 'item2',
            columns: date
          }

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/11 18:36

    ということは1つにまとめとくことができないんですね。。。汗
    了解しました。

    キャンセル

0

状態としてisActiveがあるのですが、それを td 毎に持っていないので個別の動作ができないのではないでしょうか?
したがって、各itemにisActiveを持てば解決するのではないかと思います。

const demo = new Vue({
    el: '#demo2',
    data: {
        items: [
            {date: '1', message: 'nie można', isActive: true },
            {date: '2', message: 'nie można', isActive: true },
            {date: '3', message: 'nie można', isActive: true },
            {date: '4', message: 'nie można', isActive: true },
            {date: '5', message: 'nie można', isActive: true },
            {date: '6', message: 'nie można', isActive: true },
            {date: '7', message: 'nie można', isActive: true },
        ]
    },
    methods:{
        empty:function(index){
          this.items[index].isActive = ! this.items[index].isActive;
        }
    }
});

下記に動くサンプルを置きます

https://jsfiddle.net/euledge/3gozgbj9/11/

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/10 12:26

    回答ありがとうございます、返答は本文の方に追加いたしました。

    キャンセル

0

   rows :[
        {time: '1', message: "9:00-10:00"},
        {time: '2', message: "10:00-11:00"},
        {time: '3', message: "11:00-12:00" },
        {time: '4', message: "12:00-13:00" },
        {time: '5', message: "13:00-14:00" },
        {time: '6', message: "14:00-15:00" },
        {time: '7', message: "15:00-16:00" },
        {time: '8', message: "16:00-17:00" },
        {time: '9', message: "18:00-19:00" },
        {time: '10', message: "19:00-20:00" },
        {time: '11', message: "20:00-21:00" },
    ],
    columns: [
        {date: '1', message: 'nie można' ,isActive: false},
        {date: '2', message: 'nie można' ,isActive: false},
        {date: '3', message: 'nie można' ,isActive: false},
        {date: '4', message: 'nie można' ,isActive: false},
        {date: '5', message: 'nie można' ,isActive: false},
        {date: '6', message: 'nie można' ,isActive: false},
        {date: '7', message: 'nie można' ,isActive: false},
    ]

ではそうなっちゃいますね。

rows :[
        {time: '1', message: "9:00-10:00", 
          columns: [
          {date: '1', message: 'nie można' ,isActive: false},
          {date: '2', message: 'nie można' ,isActive: false},
          {date: '3', message: 'nie można' ,isActive: false},
          {date: '4', message: 'nie można' ,isActive: false},
          {date: '5', message: 'nie można' ,isActive: false},
          {date: '6', message: 'nie można' ,isActive: false},
          {date: '7', message: 'nie można' ,isActive: false},
        ]},
        {time: '2', message: "10:00-11:00", 
          columns: [
          {date: '1', message: 'nie można' ,isActive: false},
          {date: '2', message: 'nie można' ,isActive: false},
          {date: '3', message: 'nie można' ,isActive: false},
          {date: '4', message: 'nie można' ,isActive: false},
          {date: '5', message: 'nie można' ,isActive: false},
          {date: '6', message: 'nie można' ,isActive: false},
          {date: '7', message: 'nie można' ,isActive: false},
        ]},
       以下略
   ],
]

テーブルの構造どおり上記のようにしないと1マスづつにはならないです

説明省いちゃってますけど、methodで渡す値も rowのindexと columnのindexが必要です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/10 14:37

    回答ありがとうございます、「回答を受けての追加②」と本文に追加いたしました。

    キャンセル

0

まず、誤解されているようなので訂正させていただきます。

indexプロパティが追加されている(?)イメージだと思っております

ですが、indexは v-forの構文の中で配列のインデクスとしてサポートされているものなのでオブジェクトにindexというプロパティを用意する必要はありません。

<td v-for="(row,index) in rows">
  <td>{{index}}</td>
  <td>{{row.name}}</td>
</td>

Vue.js ガイドより
v-for で配列に要素をマッピングする

となると、rowとcolumnで同じ名前のindexは使用できないので名前は分けましょう。
rowIndex, colIndex とか
(indexという名前がインデクスを表すのではなく第2引数がインデクスになります)

https://jsfiddle.net/euledge/3gozgbj9/25/

クラスのOn/Offだけなら、ふとisActiveもindexもいらないんじゃねと思いました。
isActive,indexを使用しないバージョンも下記に載せておきます
https://jsfiddle.net/euledge/3gozgbj9/38/
ただし、クリックされているかどうかをデータとして残す必要がある場合は isActiveは必要になりますので上のパターンで行う必要があります。

Vue.js ガイドより
メソッドイベントハンドラ

遠回りさせてしまいすみません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/11 14:03

    「回答を受けての追加③」に本文中にて返答いたしました。

    キャンセル

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

  • ただいまの回答率 90.11%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる