\n\n\n
\n
\n
\n
\n\n\n~~~\n\n\n\n#### 質問\n- Tableクラスの中で宣言されたTdクラスから,Tableクラスのメソッドを呼び出す方法について\n- このクラス設計では呼び出せないのであれば,どうすれば良いか最適解を教えていただきたい\n\n\n以上,よろしくお願い致します.","answerCount":2,"upvoteCount":0,"datePublished":"2022-12-04T03:31:56.551Z","dateModified":"2022-12-05T20:04:53.000Z","acceptedAnswer":{"@type":"Answer","text":"> Tableクラスの中で宣言されたTdクラスから,Tableクラスのメソッドを呼び出す方法\n\n変更を最小限にするならば、下記のようにすればよいのではないでしょうか。\n\n+ Table 内でTd (ボタン)を生成するときに、自分自身のインスタンスを渡すようにする。\n```diff\n\nclass Table {\n略\n createOneLine(num) {\n 略\n- let func = new Td(index, \"+\", \"button\");\n+ let func = new Td(index, \"+\", \"button\", this);\n 略\n }\n```\n\n+ Td のコンストラクタで、table のインスタンスを受け取るようにしておく。\n```diff\n class Td {\n- constructor(index, text, childTag) {\n+ constructor(index, text, childTag, table) {\n this.index = index;\n this.tdElem = document.createElement('td');\n this.text = text;\n this.childTag = childTag;\n+ this.parentTable = table;\n this._setTd()\n }\n```\n\n+ ボタンをクリックしたら、table の setNewOneLine メソッドを呼び出す。\n```diff\nclass Td {\n略\n createBtnElem() { // ボタンをtdElementの子要素として追加\n略\n btnElem.addEventListener('click', () => {\n // ここに新しく行を追加する処理を書きたい.\n+ this.parentTable.setNewOneLine((this.index + 1.1).toFixed(1))\n });\n\n this.tdElem.appendChild(btnElem);\n }\n```\n\n\n\n修正後のコード全体:\n```js\n // main.js\n\n const FLOAT_SUB = (num1, num2) => Number((num1 - num2).toFixed(2));\n\n class Table {\n constructor(row) {\n this.TABLE_ELEM = document.createElement('table');\n this.TBODY_ELEM = document.createElement('tbody');\n this.row = row; // 行数\n this.tableArray = new Array(); // tbodyの中身 \"tr\" を保持\n this._setTable();\n }\n\n get table() {\n return this.TABLE_ELEM;\n }\n\n _setTable() {\n\n for (let i = 1; i <= this.row; i++) {\n this.TBODY_ELEM.appendChild(this.createOneLine(i));\n }\n\n this.TABLE_ELEM.appendChild(this.TBODY_ELEM);\n }\n\n createOneLine(num) {\n let trElem = document.createElement('tr');\n let index = FLOAT_SUB(num, 1);\n let th = new Th(index, num);\n let text = new Td(index, \"Text is written here.\", \"input\");\n let func = new Td(index, \"+\", \"button\", this);\n trElem.appendChild(th.thElem);\n trElem.appendChild(text.tdElem);\n trElem.appendChild(func.tdElem);\n\n this.tableArray[index] = trElem;\n return trElem;\n }\n\n /**\n * 新しく行を追加する\n * @param {Number} num tableArray に新しく追加する要素番号-1 \n */\n setNewOneLine(num) {\n this.tableArray[FLOAT_SUB(num, 1.1)].after(this.createOneLine(num));\n this.row++;\n }\n }\n\n /**\n * td エレメントの作成\n * @param {Number} index TableクラスのtableArrayの要素番号\n * @param {String} text tdの子要素のテキスト\n * @param {String} childTag tdの子要素のタグネーム\n * @returns 裏返すコマの座標と裏返すコマの数\n */\n class Td {\n constructor(index, text, childTag, table) {\n this.index = index;\n this.tdElem = document.createElement('td');\n this.text = text;\n this.childTag = childTag;\n this.parentTable = table;\n this._setTd()\n }\n\n _setTd() {\n if (this.childTag == \"button\") {\n this.createBtnElem();\n } else {\n this.createInputElem();\n }\n }\n\n createInputElem() { // inputをtdElementの子要素として追加\n let inputElem = document.createElement('input');\n inputElem.type = this.text;\n inputElem.value = this.text;\n this.tdElem.appendChild(inputElem);\n }\n createBtnElem() { // ボタンをtdElementの子要素として追加\n let btnElem = document.createElement('button');\n btnElem.type = \"button\";\n btnElem.innerText = this.text;\n\n btnElem.addEventListener('click', () => {\n // ここに新しく行を追加する処理を書きたい.\n this.parentTable.setNewOneLine((this.index + 1.1).toFixed(1))\n });\n\n this.tdElem.appendChild(btnElem);\n }\n }\n\n class Th {\n constructor(index, text) {\n this.index = index;\n this.thElem = document.createElement('th');\n this.text = text;\n this._setTh();\n }\n\n _setTh() {\n this.thElem.innerText = this.text;\n }\n }\n\n\n window.onload = () => {\n let table = new Table(3);\n document.getElementById('hoge').appendChild(table.table);\n\n table.setNewOneLine(1.1); // 1行目の+が押されたと仮定\n table.setNewOneLine(1.2); // 1.1行目の+が押されたと仮定\n }\n\n```\n\n\n","dateModified":"2022-12-05T11:04:53.194Z","datePublished":"2022-12-04T04:29:36.529Z","upvoteCount":0,"url":"https://teratail.com/questions/8714z1v4c83rfg#reply-qfp7822jte1trh"},"suggestedAnswer":[{"@type":"Answer","text":"qnoirさまの回答のように`Table`インスタンスを渡しておくのが最も変更が少ないかと思います。\n\n別案1: イベント委譲\nボタンにイベントを付けるのではなく、`Table` クラスが `this.TABLE_ELEM.addEventListener('click', e => ...)` してイベントを処理します。どのボタンが押されたかわかるように、ボタンに `data-index` 属性でも付けて `index` 値がわかるようにしておきましょう。\n\n別案1: カスタム要素\n`Table` クラスをカスタム要素にすれば、要素をクラスのインスタンスとして扱えるので `event.target.closest('my-table')` などで簡単に `Table` インスタンスが得られます。\n残念ながらSafariでは[カスタマイズされた組み込み要素](https://developer.mozilla.org/ja/docs/Web/Web_Components/Using_custom_elements#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E3%81%95%E3%82%8C%E3%81%9F%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF%E8%A6%81%E7%B4%A0)が非対応なので、[自律カスタム要素](https://developer.mozilla.org/ja/docs/Web/Web_Components/Using_custom_elements#%E8%87%AA%E5%BE%8B%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E8%A6%81%E7%B4%A0)で`display: table` などを指定する必要があります。\n","dateModified":"2022-12-04T15:20:33.132Z","datePublished":"2022-12-04T15:20:33.132Z","upvoteCount":1,"url":"https://teratail.com/questions/8714z1v4c83rfg#reply-j4xi2czdbtdd7j","comment":[]}],"breadcrumb":{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"トップ","url":"https://teratail.com"},{"@type":"ListItem","position":2,"name":"JavaScriptに関する質問","url":"https://teratail.com/tags/JavaScript"},{"@type":"ListItem","position":3,"name":"JavaScript","url":"https://teratail.com/tags/JavaScript"}]}}}
質問するログイン新規登録
JavaScript

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

Q&A

解決済

2回答

1102閲覧

【JS】 入れ子になったクラスのメソッドの呼び出し方法がわかりません.

ymymymymy

総合スコア9

JavaScript

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

0グッド

0クリップ

投稿2022/12/04 03:31

0

0

【JS】 入れ子になったクラスのメソッドの呼び出し方法がわかりません.

イメージ説明

↑ 後から行を追加できるエディタをtable要素を用いて作っています.

実現したいこと

「+」ボタンが押されたら,その直下に新しく行(tr要素以下)を追加したい.

問題点

現状はTdクラスでクリックイベントの処理を記述していて,Tdクラスから新しく行を追加するTableクラスの "setNewOneLine" メソッドをどう呼び出せばいいのかがわかりません.


下記にコードの全文を記述しています.

js

1// main.js 2 3const FLOAT_SUB = (num1, num2) => Number((num1 - num2).toFixed(2)); 4 5class Table { 6 constructor(row) { 7 this.TABLE_ELEM = document.createElement('table'); 8 this.TBODY_ELEM = document.createElement('tbody'); 9 this.row = row; // 行数 10 this.tableArray = new Array(); // tbodyの中身 "tr" を保持 11 12 this._setTable(); 13 } 14 15 get table() { 16 return this.TABLE_ELEM; 17 } 18 19 _setTable() { 20 21 for(let i = 1; i <= this.row; i++) { 22 this.TBODY_ELEM.appendChild(this.createOneLine(i)); 23 } 24 25 this.TABLE_ELEM.appendChild(this.TBODY_ELEM); 26 } 27 28 createOneLine(num) { 29 let trElem = document.createElement('tr'); 30 let index = FLOAT_SUB(num, 1); 31 let th = new Th(index, num); 32 let text = new Td(index, "Text is written here.", "input"); 33 let func = new Td(index, "+", "button"); 34 trElem.appendChild(th.thElem); 35 trElem.appendChild(text.tdElem); 36 trElem.appendChild(func.tdElem); 37 38 this.tableArray[index] = trElem; 39 return trElem; 40 } 41 42 /** 43 * 新しく行を追加する 44 * @param {Number} num tableArray に新しく追加する要素番号-1 45 */ 46 setNewOneLine(num) { 47 this.tableArray[FLOAT_SUB(num, 1.1)].after(this.createOneLine(num)); 48 this.row++; 49 } 50} 51 52/** 53 * td エレメントの作成 54 * @param {Number} index TableクラスのtableArrayの要素番号 55 * @param {String} text tdの子要素のテキスト 56 * @param {String} childTag tdの子要素のタグネーム 57 * @returns 裏返すコマの座標と裏返すコマの数 58 */ 59class Td { 60 constructor(index, text, childTag) { 61 this.index = index; 62 this.tdElem = document.createElement('td'); 63 this.text = text; 64 this.childTag = childTag; 65 66 this._setTd() 67 } 68 69 _setTd() { 70 if(this.childTag == "button") { 71 this.createBtnElem(); 72 } else { 73 this.createInputElem(); 74 } 75 } 76 77 createInputElem() { // inputをtdElementの子要素として追加 78 let inputElem = document.createElement('input'); 79 inputElem.type = this.text; 80 inputElem.value = this.text; 81 this.tdElem.appendChild(inputElem); 82 } 83 createBtnElem() { // ボタンをtdElementの子要素として追加 84 let btnElem = document.createElement('button'); 85 btnElem.type = "button"; 86 btnElem.innerText = this.text; 87 88 btnElem.addEventListener('click', () => { 89 console.log("btn click."); 90 91 // ここに新しく行を追加する処理を書きたい. 92 93 }); 94 95 this.tdElem.appendChild(btnElem); 96 } 97} 98 99class Th { 100 constructor(index, text) { 101 this.index = index; 102 this.thElem = document.createElement('th'); 103 this.text = text; 104 105 this._setTh(); 106 } 107 108 _setTh() { 109 this.thElem.innerText = this.text; 110 } 111} 112 113 114window.onload = () => { 115 let table = new Table(3); 116 document.getElementById('hoge').appendChild(table.table); 117 118 table.setNewOneLine(1.1); // 1行目の+が押されたと仮定 119 table.setNewOneLine(1.2); // 1.1行目の+が押されたと仮定 120 console.log(table); 121}

html

1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>hoge</title> 7 <script src="./js/main.js"></script> 8</head> 9<body> 10 <main role="main"> 11 <div id="hoge"> 12 </div> 13 </main> 14</body> 15</html>

質問

  • Tableクラスの中で宣言されたTdクラスから,Tableクラスのメソッドを呼び出す方法について
  • このクラス設計では呼び出せないのであれば,どうすれば良いか最適解を教えていただきたい

以上,よろしくお願い致します.

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

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

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

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

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

guest

回答2

0

qnoirさまの回答のようにTableインスタンスを渡しておくのが最も変更が少ないかと思います。

別案1: イベント委譲
ボタンにイベントを付けるのではなく、Table クラスが this.TABLE_ELEM.addEventListener('click', e => ...) してイベントを処理します。どのボタンが押されたかわかるように、ボタンに data-index 属性でも付けて index 値がわかるようにしておきましょう。

別案1: カスタム要素
Table クラスをカスタム要素にすれば、要素をクラスのインスタンスとして扱えるので event.target.closest('my-table') などで簡単に Table インスタンスが得られます。
残念ながらSafariではカスタマイズされた組み込み要素が非対応なので、自律カスタム要素display: table などを指定する必要があります。

投稿2022/12/04 15:20

int32_t

総合スコア22019

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

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

0

ベストアンサー

Tableクラスの中で宣言されたTdクラスから,Tableクラスのメソッドを呼び出す方法

変更を最小限にするならば、下記のようにすればよいのではないでしょうか。

  • Table 内でTd (ボタン)を生成するときに、自分自身のインスタンスを渡すようにする。

diff

1 2class Table { 34 createOneLine(num) { 5 6- let func = new Td(index, "+", "button"); 7+ let func = new Td(index, "+", "button", this); 8 略 9 }
  • Td のコンストラクタで、table のインスタンスを受け取るようにしておく。

diff

1 class Td { 2- constructor(index, text, childTag) { 3+ constructor(index, text, childTag, table) { 4 this.index = index; 5 this.tdElem = document.createElement('td'); 6 this.text = text; 7 this.childTag = childTag; 8+ this.parentTable = table; 9 this._setTd() 10 }
  • ボタンをクリックしたら、table の setNewOneLine メソッドを呼び出す。

diff

1class Td { 23 createBtnElem() { // ボタンをtdElementの子要素として追加 45 btnElem.addEventListener('click', () => { 6 // ここに新しく行を追加する処理を書きたい. 7+ this.parentTable.setNewOneLine((this.index + 1.1).toFixed(1)) 8 }); 9 10 this.tdElem.appendChild(btnElem); 11 }

修正後のコード全体:

js

1 // main.js 2 3 const FLOAT_SUB = (num1, num2) => Number((num1 - num2).toFixed(2)); 4 5 class Table { 6 constructor(row) { 7 this.TABLE_ELEM = document.createElement('table'); 8 this.TBODY_ELEM = document.createElement('tbody'); 9 this.row = row; // 行数 10 this.tableArray = new Array(); // tbodyの中身 "tr" を保持 11 this._setTable(); 12 } 13 14 get table() { 15 return this.TABLE_ELEM; 16 } 17 18 _setTable() { 19 20 for (let i = 1; i <= this.row; i++) { 21 this.TBODY_ELEM.appendChild(this.createOneLine(i)); 22 } 23 24 this.TABLE_ELEM.appendChild(this.TBODY_ELEM); 25 } 26 27 createOneLine(num) { 28 let trElem = document.createElement('tr'); 29 let index = FLOAT_SUB(num, 1); 30 let th = new Th(index, num); 31 let text = new Td(index, "Text is written here.", "input"); 32 let func = new Td(index, "+", "button", this); 33 trElem.appendChild(th.thElem); 34 trElem.appendChild(text.tdElem); 35 trElem.appendChild(func.tdElem); 36 37 this.tableArray[index] = trElem; 38 return trElem; 39 } 40 41 /** 42 * 新しく行を追加する 43 * @param {Number} num tableArray に新しく追加する要素番号-1 44 */ 45 setNewOneLine(num) { 46 this.tableArray[FLOAT_SUB(num, 1.1)].after(this.createOneLine(num)); 47 this.row++; 48 } 49 } 50 51 /** 52 * td エレメントの作成 53 * @param {Number} index TableクラスのtableArrayの要素番号 54 * @param {String} text tdの子要素のテキスト 55 * @param {String} childTag tdの子要素のタグネーム 56 * @returns 裏返すコマの座標と裏返すコマの数 57 */ 58 class Td { 59 constructor(index, text, childTag, table) { 60 this.index = index; 61 this.tdElem = document.createElement('td'); 62 this.text = text; 63 this.childTag = childTag; 64 this.parentTable = table; 65 this._setTd() 66 } 67 68 _setTd() { 69 if (this.childTag == "button") { 70 this.createBtnElem(); 71 } else { 72 this.createInputElem(); 73 } 74 } 75 76 createInputElem() { // inputをtdElementの子要素として追加 77 let inputElem = document.createElement('input'); 78 inputElem.type = this.text; 79 inputElem.value = this.text; 80 this.tdElem.appendChild(inputElem); 81 } 82 createBtnElem() { // ボタンをtdElementの子要素として追加 83 let btnElem = document.createElement('button'); 84 btnElem.type = "button"; 85 btnElem.innerText = this.text; 86 87 btnElem.addEventListener('click', () => { 88 // ここに新しく行を追加する処理を書きたい. 89 this.parentTable.setNewOneLine((this.index + 1.1).toFixed(1)) 90 }); 91 92 this.tdElem.appendChild(btnElem); 93 } 94 } 95 96 class Th { 97 constructor(index, text) { 98 this.index = index; 99 this.thElem = document.createElement('th'); 100 this.text = text; 101 this._setTh(); 102 } 103 104 _setTh() { 105 this.thElem.innerText = this.text; 106 } 107 } 108 109 110 window.onload = () => { 111 let table = new Table(3); 112 document.getElementById('hoge').appendChild(table.table); 113 114 table.setNewOneLine(1.1); // 1行目の+が押されたと仮定 115 table.setNewOneLine(1.2); // 1.1行目の+が押されたと仮定 116 } 117

投稿2022/12/04 04:29

編集2022/12/05 11:04
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.29%

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

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

質問する

関連した質問