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

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

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

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

Q&A

解決済

3回答

2190閲覧

Javascript: 引数が空の時クリック処理を実行するとエラーになってしまう

nanase21

総合スコア144

JavaScript

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

0グッド

2クリップ

投稿2019/04/09 18:40

編集2019/04/21 03:02

最初に/お詫び
前回質問した内容とほぼ同じ内容になっています。

#前提
クリック時の処理
問題なくクリック処理が実行されると、「エラーは取れましたね」とアラートが表示される。

起きているエラー
schedule.setHoliday()の中が空の時カレンダーをクリックするとエラーになってしまう。

関数の処理について
setHoilday関数では、引数の値を元に定休日の日には表示されているカレンダーのセルが「×」と表示される処理になっています。

エラーの原因
setHoilday()の引数が関数に返された時に値が空の状態だと関数内の処理が実行されないため
setHoilday(1,2,4)と一つでも値が入っていれば、エラーは起きない。

どうしたいのか
定休日を設定したくない時はschedule.setHoliday()を空で返したい。

コード量が多いためcodepenに関連する全コードを載せています。
codepen 全コード

#実現したいこと
現状では、定休日を最低1日セットしないとエラーが出てしまうので、それをsetHoilday()と定休日をセットしない時でもクリック時にアラートを表示できるようにしたい。

#追記
ご指摘を受けた点
codepenのcssとjsを分けました。
コード量が文字数上、全てお載せすることができないため、該当するコードを追記しました。

該当コード

js

1 setHoliday (...dayNo) { 2 let 3 year = this.current.getFullYear (), 4 start = new Date (year, 0, 1), 5 end = new Date (year, 12, 1), 6 7 b = new Date (Date.UTC (1970,0,1, 0, 0)),//列のスタート時間 8 e = new Date (Date.UTC (1970,0,1,24, 30)),//列の終了時間 9 s = new Date (Date.UTC (1970,0,1, 0,30));//列の感覚調整時間 10 11 //schedule.setHoliday();の時コンソール結果が配列が空になっている。 12 console.log(dayNo); 13 14 dayNo.forEach (n => { 15 let current = new Date (start); 16 17 current.setDate (7 - current.getDate () + n); 18 19 for (; current < end; current.setDate (current.getDate () + 7)) { 20 let idx = F (current); 21 22 for (let c = b; c < e; c = new Date (+s + (+c))) { 23 let key = I (c); 24 if (! this.plan[key]) 25 this.plan[key] = [ ]; //ここの配列が空によりエラーが起きている? 26 this.plan[key][idx] = true; 27 } 28 } 29 }); 30 31 return this; 32 } 33 34 // 定休日と昼休みの設定 35 //0:sun 1:mon 2:tue 3:wed 4:thu 5:fri 6:sat 36 //setHolidayを設定しないとエラーが起きる。setHoliday()だとエラーになる。なんで? 37 schedule.setHoliday(1).setLunchTime (0, 2, 4, 6); 38 39 //クリック処理 40 table.addEventListener('click', event => { 41 const target = event.target; 42 43 if (target.nodeName !== 'TD') 44 return; 45 46 if ('◎' !== target.textContent) 47 return; 48 49 let booktime = parseInt (document.querySelector ('#booktime').value, 10); 50 //表の始まりの日付 51 let cur = schedule.current; 52 //クリック時の表の(セル)座標x 53 let x = target.cellIndex; 54 //クリック時の表の(セル)座標y 55 let y = target.parentNode.rowIndex - 2; 56 //クリックされた列の日付を取得 57 let tgt = new Date (cur); 58 tgt.setDate (tgt.getDate () + x -1); 59 //その日のスケジュールを取得 60 ////schedule.setHoliday();の時下記のコードでエラーが発生 61 let plan = Schedule.getDayPlan (schedule, tgt); 62 // console.log(plan); 63 //plan から9時~15時までを抜き出す 64 plan = plan.slice (18, 31); 65 //予約コースの判定 66 let rng = booktime / 30 |0; 67 plan = plan.slice (y, y + rng); 68 69 if (rng === plan.length && plan.every (a=> !a[1])){ 70 //console.log (rng ? 'ok': 'Invalid'); 71 var id = Array.from(document.getElementsByName('id'), x => x.value); 72 73 if (!(target.closest('tbody') && 1 <= target.cellIndex && target.cellIndex <= 14)) { 74 return true; 75 } 76 const 77 time = target.parentNode.cells[0].textContent, 78 table = target.closest('table'), 79 date = table.tHead.rows[1].cells[target.cellIndex - 1].textContent.replace(/[^0-9]/g, ''), 80 ymrow = table.tHead.rows[0], 81 ym = (target.cellIndex <= ymrow.cells[1].colSpan ? ymrow.cells[1] : ymrow.cells[2]).textContent; 82 83 let 84 value = ym + date + '日' + time, 85 param = document.getElementById( "booktime" ).value; 86 //newに飛ぶ 87 alert('エラーは取れましたね'); 88 //window.location.href = `new.${id}`+`confirm?datetime=${value + '-' + param + '分コース' + id}`; 89 }else{ 90 alert("その時間帯は予約は出来ません。"); 91 } 92 }, false);

問題の再現方法
通常処理
schedule.setHoliday(1)orschedule.setHoliday(1,3,6)とsetHolidayの中に、数字がある場合、カレンダー内の◎のセルをクリックすると「エラーは取れましたね」とアラートが表示されます。

エラーが起きる時
schedule.setHoliday()とsetHolidayの中に、数字がない場合、カレンダー内の◎のセルをクリックしてもアラートが表示されなくなります。

エラーが出る時のcodepenプロジェクト
エラー詳細

#解決した方法
私の力ではどうしても分からなかったため、@hai_haiさんからご教示いただきました。
a = Array(24).fill(0).reduce((a,b,c)=>(b=('0'+c).slice(-2),[...a,b+':00',b+':30']),[]).reduce((a,b)=>(a[b]=Array(366).fill(false),a),{});

実際のコード

js

1setHoliday (...dayNo) { 2 let 3 year = this.current.getFullYear (), 4 start = new Date (year, 0, 1), 5 end = new Date (year, 12, 1), 6 // ここでdayNoが0の時に実行される処理。全てを初期化する。this.planにaを代入する。 7 a = Array(24).fill(0).reduce((a,b,c)=>(b=('0'+c).slice(-2),[...a,b+':00',b+':30']),[]).reduce((a,b)=>(a[b]=Array(366).fill(false),a),{}), 8 b = new Date (Date.UTC (1970,0,1, 0, 0)),//列のスタート時間 9 e = new Date (Date.UTC (1970,0,1,24, 30)),//列の終了時間 10 s = new Date (Date.UTC (1970,0,1, 0,30));//列の感覚調整時間 11 //setHolidayのdayNoに戻り値が返されるので、dayNoの中の配列が空かどうか確認し、空の場合のみにthis.planにaを代入する。 12 if (!dayNo.length > 0){ 13 this.plan = a; 14 } 15 dayNo.forEach (n => { 16 let current = new Date (start); 17 18 current.setDate (7 - current.getDate () + n); 19 20 for (; current < end; current.setDate (current.getDate () + 7)) { 21 let idx = F (current); 22 23 for (let c = b; c < e; c = new Date (+s + (+c))) { 24 let key = I (c); 25 if (! this.plan[key]) 26 this.plan[key] = [ ]; 27 this.plan[key][idx] = true; 28 } 29 } 30 });

#今後について
今回質問させていただくにあたり、ご回答して頂いた多数の方から身の丈にあったところから勉強していくべきとご指摘を受けたことを踏まえ、私もその通りだと感じました。
今後については、javascriptをちゃんと勉強した上で再度カレンダーの実装について取り組んでいきたいと思います。
何度も質問してしまいご迷惑をおかけして申し訳ございませんでした。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2019/04/09 23:29

タイトルにタグぽい書き方のものは不要であーる
退会済みユーザー

退会済みユーザー

2019/04/09 23:46

原因:this.plan が初期化されていないから。 というか、配列の指定値が undefined でもそれを判断して動作するように工夫する。
m.ts10806

2019/04/10 00:17

codepenにあげるのでしたらCSS、jsはエリアをきちんと分けてほしいです・・・。
kei344

2019/04/10 02:09

問題の再現方法を提示してください。また、コードは外部サービスだけでなく、質問文にコードブロックでお書きください。
yambejp

2019/04/10 02:17

肥大化させてからエラーがとれないというのは開発方針としては最悪 自分で追いかけられないならもう少し簡単なモデルまで戻ってやるのが賢明
kei344

2019/04/10 03:22 編集

codepenでの問題の再現方法を提示してください。
kei344

2019/04/10 04:07

「setHolidayの中に、数字がない場合」のcodepenを別に用意してください。また、「クリックするとエラーになってしまう。」ではなくエラー文をそのまま提示してください。
nanase21

2019/04/10 10:14

@hai_haiさん ご教示いただきありがとうございます。 配列の指定値がundefinedの時、どのような処理を記述すればいいのでしょうか?
nanase21

2019/04/10 10:16

@kei344さん 質問内に数字がない場合ののcodepenを別に用意しました。
guest

回答3

0

原因:this.plan が初期化されていないから。
というか、配列の指定値が undefined でもそれを判断して動作するように工夫する。

既に上記のように指摘がありますが、
this.plan[キー][キー] をあらかじめfalseで埋めるか(初期化するか)、
return idx.map (i => [i, !!obj.plan[i][dn]]); の部分で obj.plan[i] が有るか無いかを判定して処理するか、
すればエラーは起こらなくなります。

下記部分はJavaScriptでは特に問題というわけではないですが、意図していないなら全角空白の判別できるエディタを使用されることをお勧めします。

js

1/* 全角スペース↓ */ 2for(let i=0;i<num.length;i++){/*   */ 3 schedule.setHoliday (num[i]); 4}

投稿2019/04/10 15:11

kei344

総合スコア69407

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

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

nanase21

2019/04/10 16:02

obj.plan[i]が定義されていないことがわかったのでreturn idx.map (i => [i, !!obj.plan[dn]]);とするとエラーを取ることができました。そのため、obj.plan[i]があるか無いかによってreturn文の内容を変更しようとif文で条件を書いてみたのですがどのように書けば良いか分からず条件分岐できませんでした。 もしお分かりであれば、ご教示いただけないでしょうか? if (plan[i].length > 0)としてみたのですが、条件分岐できませんでした。。。
kei344

2019/04/10 16:04

試したコードはどれでしょう。map の関数を1行で書いていますが、意味がわかって使っていますか。
nanase21

2019/04/10 16:09

https://codepen.io/nanase/pen/pBevoj?editors=0010 上記のcodepenで該当箇所をreturn idx.map (i => [i, !!obj.plan[dn]]);としました。 mapメソッドについては、既存の配列を呼び出し、新規の配列を生成している処理だと認識しているのですが違いますでしょうか?
kei344

2019/04/10 16:16

!!obj.plan[dn] にしたらobj.plan[i][dn]に値があるときに判定がおかしくなるでしょ。 > mapメソッド アロー関数で処理されているから1行になっているのがわかっているか、というつもりでした。 また、「既存の配列を呼び出し、新規の配列を生成している」だけではありません。値を処理するための関数をそれぞれ実行してから新しい配列にしています。 【アロー関数 - JavaScript | MDN】 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functionsArray.prototype.map() - JavaScript | MDN】 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map
nanase21

2019/04/10 16:32 編集

!!obj.plan[dn]の時に、[i]が存在するとエラーが出るのであらかじめ return idx.map (i => [i, !!obj.plan[i][dn]]);とreturn idx.map (i => [i, !!obj.plan[dn]]); を用意し、[i]の有無判定を行ってエラーを回避しようとしたのですが、やり方としては好ましく無いのでしょうか? 追記 @kei344さんがobj.plan[i]の有無の判定を行う場合、どのような処理を書くのかアドバイス頂けないでしょうか?
kei344

2019/04/10 16:33

> やり方としては好ましく無いのでしょうか? 書いていないコードについて、回答はしていませんよ。 アロー関数についてはコメントが無いため、こちらの言っている意味がわからなかったと解釈しました。アロー関数を知らずにここまで長いコードを書いているとはちょっと思えません。 開発された方に修正や継続した開発を依頼できない状態なのでしょうか。
nanase21

2019/04/10 17:21

アロー関数に関しては、ES6からできた構文でなんとなく書くことはできるのですが、詳しくありません。 カレンダーに関しては他の人のteratailの投稿を元に作っていまして分からない箇所を質問を投稿して勉強で色々いじっているだけなので依頼とかでは無いです。 それと、やり方としては汚いのですが、setHoliday (...dayNo)に返された値をstatic getDayPlan内で取得しif文で判定を行えば意図した処理に出来るかもしれないので試してみます。
退会済みユーザー

退会済みユーザー

2019/04/11 01:08

undefined ということは、予約できるということなので、this.plan も書き換える。簡単な事さ!
nanase21

2019/04/11 06:28

@hai_haiさん 原因:this.plan が初期化されていないから。 についてなんですが、this.planの書き換え方が分からないのですがコメントで初期化とおっしゃっていたので下記のようにしてみたのですがどのように書き換えれば良いかもう少しアドバイスをいただくことは出来ないでしょうか? this.plan[key] = new Array();
退会済みユーザー

退会済みユーザー

2019/04/11 08:51

自分で解決できる「力」が欠如しているのですか? 適当に休みをセットしてみて、console.log (schedule.plan)として中身を見てみることでも思いついてください。構造が見えます。
nanase21

2019/04/18 16:55

@hai_hai さん 何度も何度も申し訳ございません。 console.log (schedule.plan)やsetLunchtimeを空にしてみたりと試してはみたのですがどうしても私の力では分からないため、もう少しだけどのようにすればよいかご教示頂けないでしょうか? ご教示頂いた初期化ついてですが、どうしても書き方が分からないためご教示いただけると幸いです。
Lhankor_Mhy

2019/04/20 01:59

横からすみません。 初期化とは、setHoliday関数の中の for (let c = b; ...でやっていることですよ。 setHoliday関数 は休みの日だけ初期化しているようです。
nanase21

2019/04/20 11:34

@Lhankor_Mhy さん ご教示いただきありがとうございます。 for文内で初期化が行われていたんですね。それでは、休みがセットされていない時はどのように初期化を行えばいいのでしょうか? 例えば休みがセットされているかをifで条件分岐し、休みがセットされていない時のfor文を作ればいいのでしょうか? もしお分かりでしたらご教示いただけると幸いです。
Lhankor_Mhy

2019/04/20 11:37

私なら、setHoliday関数ではなく、最初に全部初期化するかもしれませんね。
nanase21

2019/04/20 12:44

@Lhankor_Mhy さん 全部、初期化するやり方もあるのですね。 全部初期化を行う場合、どこを初期化すればいいのかご教示頂けないでしょうか?
Lhankor_Mhy

2019/04/20 12:54

もちろん、this.plan です。 今のところ、this.plan = [] と初期化されていますから、これを、 this.plan = {"00:00":[false,false, ... ],"00:30":[false,false, ... ], ... } にするってことですね。
nanase21

2019/04/20 15:41

@Lhankor_Mhy さん this.planのかっこの中は30分ごとにfalseと書いていくのでしょうか?
kei344

2019/04/20 15:45

To: Lhankor_Mhyさん 出来れば回答して、そこのコメントでやり取りをお願いできませんか?
guest

0

ベストアンサー

最初に初期化する。

身の丈に合った仕事をすべきです。
「このコードをどこに、どのように埋め込めばよいのですか?」
というのなら、もうあきらめたほうがよい。
(1行で済むようなことを・・・)

javascript

1let a = Array(24).fill(0).reduce((a,b,c)=>(b=('0'+c).slice(-2),[...a,b+':00',b+':30']),[]).reduce((a,b)=>(a[b]=Array(366).fill(false),a),{}); 2 3

投稿2019/04/20 17:38

編集2019/04/20 17:51
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

nanase21

2019/04/20 18:06

ご教示頂きありがとうございます。 一旦、カレンダーについては私の知識量ではこれ以上進めれそうにないのでjsについてちゃんと勉強してからアレンジを加えてみます。 ご迷惑をおかけして申し訳ございませんでした。
guest

0

よくわからないコードは小さく分割して、理解できた部分から実装することをお勧めします。

何十行にもわたるコードをコピー&ペーストしてしまうと、どこでエラーが起きているのかわからなくて当然ですし、それを他人に解読させるのはなかなか困難だと思います。

コードのどの部分でエラーや期待していない動作が起きているかを自分で確認した上で、その部分だけを抽出したコードを乗せた方が有効な回答も得られやすいでしょう。

投稿2019/04/20 00:46

siruku6

総合スコア1382

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問