プロが教える店舗&オフィスのセキュリティ対策術

javascriptを学習しています。
追加ボタンを押した際に「[namae]さん[nickname]を登録します。よろしいですか?」 という確認ダイアログ(confirm)を挟み、 ok ボタンを押した場合のみ入力値が追記されるように変更しなさい。
([namae]、[nickname]の部分は入力値で置換されること).という問題がありました。
キャンセルボタンを押しても追記されてしまいます。
どなたかご教授お願いいたします。

『javascript』

<script>

let tuikaTimes = 0;
let result = document.getElementById('result');
let hyoji = document.getElementById("tuikaBtn");
tuikaBtn.addEventListener('click', function () {
let namae = document.getElementById("namae");
let nickname = document.getElementById("nickname");
if( namae.value===""||nickname.value==="") { return false; }
if(!window.confirm('「'+'['+namae.value+']' + 'さん' +'['+ nickname.value +']'+ 'を登録します。よろしいですか?」')) {
return false;
}
alert('「'+'['+ namae.value + ']' + 'さん' + '[' + nickname.value + ']'+'にて登録しました。」');
tuikaTimes++;
if(tuikaTimes >= 3) {
hyoji.style.visibility="hidden";
return false;
}
});

window.addEventListener('DOMContentLoaded', ()=>{
tuikaBtn.addEventListener('click',()=>{
let tbl=result.querySelector('table');
if(!tbl){
tbl=document.createElement('table');
result.appendChild(tbl);
}
const v1=namae.value;
const v2=nickname.value;
if(v1 && v2){
const tr=[v1,v2].reduce( (x,y)=>(x.appendChild( Object.assign( document.createElement('td'),{textContent:y})),x),document.createElement('tr'));
tr.appendChild(Object.assign( document.createElement('input'),{type:'button',value:'削除',className:'del'}));
tbl.appendChild(tr);
namae.value='';
nickname.value='';
}
});
});

document.addEventListener('click',e=>{
if(e.target.matches('.del')){
tuikaTimes--; hyoji.style.visibility="visible";
e.target.closest('tr').remove();
}
});

</script>
</body>
</html>

「追加ボタンを押した際に ok ボタンを押」の質問画像

質問者からの補足コメント

  • 条件としては、
    ・名前とニックネームを3回追記したらボタンを非表示にし、それ以降は追記できないようにすること。
    ・tableタグとそれに関連するタグを利用し、入力した 名前 と ニックネーム を最大3人分までテーブル表示できるようにすること。
    ・データを3件登録して追加ボタンを消すようにしたが、削除ボタンでデータが削除され3件未満になった場合は追加ボタンを再表示させ、3件になるまで追加し直せるようにすること

    これらも同時に操作できるようにしたいです。
    宜しくお願いいたします。

      補足日時:2022/05/29 11:52

A 回答 (6件)

No3です。



>~~追記されるように変更しなさい。~~という問題がありました。
問題や課題であるのならば、それまでに学習したことの延長になっているはずです。
ですので、もしもわからないのであれば、復習をするのが最良の方法です。

>分かる範囲でご教示いただけると幸いです。
DOM操作のスクリプトは、HTMLの構造と密接に関係します。
HTMLが全く不明の状態ですので、何もわからないとも言えます。
(回答者には質問文に記されていること以外は分かりませんので)
HTMLがidやclassだらけになっていれば多少は想定できますが、それでも構造は必要ですね。
文章で回答できる範囲であれば、すでにNo3に記した通りです。


また、あちこちで同じ質問をやたら繰り返しているようですが・・
https://teratail.com/questions/rq530w2k4y136w
https://detail.chiebukuro.yahoo.co.jp/qa/questio …
https://detail.chiebukuro.yahoo.co.jp/qa/questio …
回答が無いのならまだしも、回答(=ベストアンサー)があるのにも関わらず、反応を見ていると回答の内容を理解できていないのではないかと懸念します。


ついでながら、ご質問には直接関係はありませんけれど・・
登録、削除が自由にできる操作を想定していながら、目視で確認できるにもかかわらず、毎回「登録します」の確認や、「登録しました」などのメッセージを表示するのも、UIとしてはいかがなものかと感じますけれど・・・

更に言うなら、通常は何かの登録の際には、nameあるいはnicknameが他の登録者と重複しないようにチェックを行うものと思いますが、その辺りに関して何らかの処置を考えている様にはまったく見受けられません。
ですので、ご質問のスクリプトは、いったい「何の目的で、どのようなシチュエーションを想定して」いるのかすらも推測できかねる状態です。
    • good
    • 0

No4です。



>3回目の表記で完全にボタンを非表示にするためには、

Object.assginについては、以下のサイトが参考になります。

https://developer.mozilla.org/ja/docs/Web/JavaSc …

もちろん、.style.visibility="hidden";を使っても良いと思います。
    • good
    • 0

No3さんのご指摘がもっともだと思ったので、


少し修正してみました。

なお、fetch apiはmdnに解説があります。
https://developer.mozilla.org/ja/docs/Web/API/Fe …

<input type="text" id="namae" />
<input type="text" id="nickname" />
<input type="button" id="tuikaBtn" value="追加ボタン" />
<table id="result-table">
<thead>
<tr>
<th>名前</th>
<th>ニックネーム</th>
<th>削除</th>
</tr>
</thead>
</table>
<script>

class NameTable {
constructor() {
this.data = [];
this.table = document.getElementById('result-table');
this.tbody = this.table.createTBody();
this.btn = document.getElementById("tuikaBtn");
this.input_namae = document.getElementById("namae");
this.input_nickname = document.getElementById("nickname");
}

handleEvent(e) {
if (e.target === this.btn) {
const name_value = this.input_namae.value,
nickname_value = this.input_nickname.value;
if (this.checkTsuika(name_value, nickname_value)) {
this.pushData(name_value, nickname_value);
this.createTable();
};
} else if (e.target.matches('.del')) {
this.clickDel(e.target);
}
}

pushData(name, nickname) {
/* DBなどに追加する場合は、ここでfetchなどで通信 */
this.data.push({ name: name, nickname: nickname });
window.alert(`「[${name}]さん[${nickname}]にて登録しました。」`);
this.input_namae.value = '';
this.input_nickname.value = '';
if (this.data.length > 2) {
Object.assign(this.btn, {
value: 'これ以上追記できません',
disabled: true,
});
}
}

createTable() {
while (this.tbody.firstChild) {
this.tbody.removeChild(this.tbody.firstChild);
}
this.data.forEach(d => {
const tr = this.tbody.insertRow(-1);
tr.insertCell(0).appendChild(document.createTextNode(d.name));
tr.insertCell(1).appendChild(document.createTextNode(d.nickname));
const input_del = document.createElement('input');
Object.assign(input_del, {
type: 'button',
value: '削除',
className: 'del',
});
tr.insertCell(2).appendChild(input_del);
});
}

checkTsuika(name, nickname) {
if (name === "" || nickname === "") {
window.alert('両方入力してください');
return false;
}
if (!this.data.every(d => d.name !== name)) {
window.alert(`${name}さんはすでに登録されています`);
return false;
}
return window.confirm(`「[${name}]さん[${nickname}]を登録します。よろしいですか?」`);
}

clickDel(target) {
/* fetchなどで削除を送信 */
window.alert('削除しました');
const dels = [...this.tbody.querySelectorAll('.del')];
this.data = this.data.filter((_, i) => dels[i] !== target);
this.createTable();
Object.assign(this.btn, {
value: '追加ボタン',
disabled: false,
});
}
}

// 実行
window.addEventListener('DOMContentLoaded', () => {
const table = new NameTable();
document.addEventListener('click', table, false);
});

</script>
    • good
    • 0
この回答へのお礼

ご指導ありがとうございます。
参考にさせて頂きます。
3回目の表記で完全にボタンを非表示にするためには、
value: 'これ以上追記できません',
ここを変える必要がありますよね。
調べておりますが、分かる範囲でご教示いただきたいです。

お礼日時:2022/05/29 18:33

こんにちは



>キャンセルボタンを押しても追記されてしまいます。
confirmの戻り値を元に、処理を制御すれば良いのですが、そうなっていませんよね?

confirmで「OK」を押したときには、Trueが返されますので、
if( confirm("~~")) {
// 登録処理
}
という流れにしておけば良いのですが、ご提示のスクリプトでは
 ・「登録します」というメッセージを表示する
 ・既登録数によって、ボタンの表示/非表示を制御する
だけの内容になっています。

一方で、実際の登録処理は、confirmとは無関係に、無条件で処理されるように設定(=addEventListener)されています。
ですので、ご質問のようなことになっていると考えられます。
このあたりの、処理の制御を修正なされば、意図通りの動作になるでしょう。


なお、ご質問には関係ありませんけれど・・
 ・同じ名前でも何度でも登録可能
 ・「登録」と言っても、実際にはどこにも登録してはいない
  (リロードすれば、白紙状態に戻る)
となっており、実際には何をなさりたいのかも不明です。

また、HTMLが不明ですので、ざっと見ただけですけれど・・
 ・tableが存在しない場合も想定しているが、実際に起こり得る状態なのか
 ・tr、tdの生成に大層持って回った記述をなさっていますけれど・・・
などの点も疑問です。
    • good
    • 0
この回答へのお礼

ご指導ありがとうございます。
至らぬ点ばかりで大変申し訳ございません。
addEventListenerとreturn falseを同時に使用しても効かないことがわかりました。
調べておりますが、処理の仕方がうまく行っておりません。
分かる範囲でご教示いただけると幸いです。

お礼日時:2022/05/29 18:36

こんなふうでしょうか。



<input type="text" id="namae" />
<input type="text" id="nickname" />
<input type="button" id="tuikaBtn" value="追加ボタン" />
<div id="result">
<table></table>
</div>
<script>

let tuikaTimes = 0;
const result = document.getElementById('result');
const tbl = result.querySelector('table');
if (!tbl) {
tbl = document.createElement('table');
result.appendChild(tbl);
}
const hyoji = document.getElementById("tuikaBtn");

function clickTsuika() {
const namae = document.getElementById("namae");
const nickname = document.getElementById("nickname");
const v1 = namae.value;
const v2 = nickname.value;
if (v1 === "" || v2 === "") { return false; }
if (!window.confirm(`「[${v1}]さん[${v2}]を登録します。よろしいですか?」`)) {
return false;
}
const tr = [v1, v2].reduce((x, y) => (x.appendChild(Object.assign(document.createElement('td'), { textContent: y })), x), document.createElement('tr'));
tr.insertCell(-1).appendChild(Object.assign(document.createElement('input'), { type: 'button', value: '削除', className: 'del' }));
tbl.appendChild(tr);
alert(`「[${v1}]さん[${v2}]にて登録しました。」`);
namae.value = '';
nickname.value = '';
tuikaTimes++;
if (tuikaTimes >= 3) {
hyoji.style.visibility = "hidden";
return false;
}
}

function clickDel(e) {
tuikaTimes--;
hyoji.style.visibility = "visible";
e.target.closest('tr').remove();
}

// 実行
window.addEventListener('DOMContentLoaded', () => {
document.addEventListener('click', e => {
if(e.target.matches('#tuikaBtn')) {
clickTsuika();
}else if(e.target.matches('.del')) {
clickDel(e);
}
});
});

</script>
    • good
    • 0

もしかしたらこんな感じかもしれません。



<input type="text" id="namae" />
<input type="text" id="nickname" />
<input type="button" id="tuikaBtn" value="追加ボタン" />
<div id="result">
<table></table>
</div>
<script>

let tuikaTimes = 0;
let result = document.getElementById('result');
let hyoji = document.getElementById("tuikaBtn");

window.addEventListener('DOMContentLoaded', () => {
hyoji.addEventListener('click', function () {
let namae = document.getElementById("namae");
let nickname = document.getElementById("nickname");
if (namae.value === "" || nickname.value === "") { return false; }
if (!window.confirm('「' + '[' + namae.value + ']' + 'さん' + '[' + nickname.value + ']' + 'を登録します。よろしいですか?」')) {
return false;
}
alert('「' + '[' + namae.value + ']' + 'さん' + '[' + nickname.value + ']' + 'にて登録しました。」');
tuikaTimes++;
if (tuikaTimes >= 3) {
hyoji.style.visibility = "hidden";
return false;
}
let tbl = result.querySelector('table');
if (!tbl) {
tbl = document.createElement('table');
result.appendChild(tbl);
}
const v1 = namae.value;
const v2 = nickname.value;
if (v1 && v2) {
const tr = [v1, v2].reduce((x, y) => (x.appendChild(Object.assign(document.createElement('td'), { textContent: y })), x), document.createElement('tr'));
tr.appendChild(Object.assign(document.createElement('input'), { type: 'button', value: '削除', className: 'del' }));
tbl.appendChild(tr);
namae.value = '';
nickname.value = '';
}
});
});

document.addEventListener('click', e => {
if (e.target.matches('.del')) {
tuikaTimes--; hyoji.style.visibility = "visible";
e.target.closest('tr').remove();
}
});
    • good
    • 0
この回答へのお礼

お忙しい所、ご回答ありがとうございます。
大変感謝いたします。
やってみたところ、キャンセルボタンがしっかりと動いてくれました。
ただ、条件にある入力した 名前 と ニックネーム を最大3人分までテーブル表示できるようにすること、データを3件入力して追加ボタンを消すようにしたが、削除ボタンでデータが削除され3件未満になった場合は追加ボタンを再表示させ、3件になるまで追加し直せるようにすることができなくなったため、調べている所です。
もしお分かりであれば、ご教授いただけると幸いです。

お礼日時:2022/05/29 11:46

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!