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

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

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

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

Q&A

解決済

3回答

38864閲覧

【JavaScript】formの値を、jsonに変換して、postしたい。そして、action先に遷移したい。

hnkyi

総合スコア14

JavaScript

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

0グッド

0クリップ

投稿2016/11/22 02:51

編集2016/11/22 05:47

##やりたい事
formの値を、jsonに変換して、postしたい。
そして、action先に遷移したい。

ちなみに、
「出来るだけフロント側で対応してほしい。(他のデータは送らずJSONだけ送ってほしい)」
と言われているため、JSON以外のformデータも全て送ってサーバ側で処理...というのはNGです。

(2016/11/22 追記)
postするのは$.ajax()でなく、$.post()でもOKです。

(2016/11/22 追記)
調べたら、
submit:画面は遷移するが、JSONは送れない?
$.ajax/$.post:画面は遷移しないが、JSONは送れる?
やりたい事は「画面は遷移したい。JSONも送りたい。」なので、どうすれば...???

##やった事

<!----- 前略 -----> <form action="hoge" method="post"> <!----- 中略 -----> </form> <!----- 後略 -----> <script> $('form').submit(function(){ // form値をJSONに変換 var data = $('form').serializeArray(); // jQueryを使ってpost $.ajax({ type: $('form').attr('method'), url: $('form').attr('action'), dataType: 'json', contentType: 'application/json', scriptCharset: 'utf-8', data: JSON.stringify(data) }); // 本来のsubmitイベントはしない return false; // 上記のままだと画面 hoge に遷移しない。 // hogeに遷移したい。 }); </script>

##環境
Ruby on Rails

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

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

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

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

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

guest

回答3

0

状況がよくわからないのですが
ajaxでpostしたあとpostしたら二重投稿になりませんか?
むしろ同じデータをおくるのであればajaxでおくらずにpostするだけでよいのでは?

仮にajaxでpostしたあとにページの遷移をするだけなら
location.hrefでデータを送らない遷移ではいけないのでしょうか?

追記

とりあえずajaxの部分はこうしてください

javascript

1<script> 2$(function(){ 3 $('form').on('submit',function(){ 4 var data = {}; 5 $(this).find('input[name]').each(function(){ 6 data[$(this).prop('name')]=$(this).val(); 7 }); 8 console.log(JSON.stringify(data)); 9 $.ajax({ 10 type: $('form').attr('method'), 11 url: $('form').attr('action'), 12 dataType: 'text', 13 data: data, 14 success:function(d){ 15 console.log(d); 16 }, 17 }); 18 return false; 19 }); 20}); 21 22</script> 23<form method="post" action="xxx.php"> 24<input type="text" name="aaa" value="123"> 25<input type="hidden" name="bbb" value="xyz"> 26<input type="submit" value="go"> 27</form> 28 29

投稿2016/11/22 03:31

編集2016/11/22 07:07
yambejp

総合スコア114503

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

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

hnkyi

2016/11/22 03:50

> ajaxでpostしたあとpostしたら二重投稿になりませんか? 本来のsubmitが動かないようにreturn false;としています。 > 同じデータをおくるのであればajaxでおくらずにpostするだけでよいのでは? フロントからJSONを送りたいので、formを送るだけのpostでは要件を満たせないです。 > 仮にajaxでpostしたあとにページの遷移をするだけなら > location.hrefでデータを送らない遷移ではいけないのでしょうか? 画面Aからaction"hoge"を実行して、hogeに遷移したいので、単なる遷移ではダメですね...申し訳ないです。
yambejp

2016/11/22 04:24

>本来のsubmitが動かないようにreturn false;としています。 それは見てわかっているのですが、その後飛び先にいくんですよね? そしたら次の2択しかないでしょ? (1)二重投稿だってわかっていてpostする (2)postせずにlocation.hrefでとぶ(ajax送信後) postしてないけどpostしたような表示にしたいというのは道理に合いません もちろんajaxでページ取得した結果をhtmlとして表示するということは可能ですが それは遷移先に移動することではありませんので
hnkyi

2016/11/22 06:40 編集

Ruby on Railsのアクション"hoge"に対してPOSTしたいので、 ただの画面遷移では意味がないです。 また、ajaxで処理するだけだとhogeの画面に遷移しないので、 ajaxを使って処理する"だけ"、というのもNGです。
yambejp

2016/11/22 07:11

ajaxの部分はサンプルをつけておました 私の認識が正しければ命題が矛盾しているためご提示のことは 実現不可能ですが、とりあえずajaxで送ることは可能です
guest

0

input要素に追加するとか。(他の要素も一緒にPOSTされますが、受け取り側で無視すればよいです)

JavaScript

1$( 'form' ).submit( function() { 2 // form値をJSONに変換 3 var data = JSON.stringify( $( 'form' ).serializeArray() ); 4 $( 'form' ).html( '<input type="hidden" name="json" value="' + data + '">' ); 5} ); // 未テスト

追記:

じゃあフォームを追加すればよいのでは?

JavaScript

1$( 'form' ).submit( function() { 2 // form値をJSONに変換 3 var data = JSON.stringify( $( 'form' ).serializeArray() ); 4 var action = $( 'form' ).attr( 'action' ); 5 $( 'form' ).after( '<form id="jsonpost" action="' + action + '"><input type="hidden" name="json" value="' + data + '"></form>' ); 6 $( 'form#jsonpost' ).submit(); 7 return false; 8} ); // 未テスト

投稿2016/11/22 03:00

編集2016/11/22 03:18
kei344

総合スコア69357

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

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

hnkyi

2016/11/22 03:07

コメントありがとうございます。 「出来るだけフロント側で対応してほしい。(他のデータは送らずJSONだけ送ってほしい)」 と言われているため、提示いただいた内容だとNGです...申し訳ございません。
kei344

2016/11/22 03:14 編集

To: hanakayui0628さん そういうことは、質問文に書いておいてください。
kei344

2016/11/22 03:14

マイナスされた方は、どの辺りが問題点なのかをコメントして置いてください。今後に生かしたいので、よろしくお願いします。
hnkyi

2016/11/22 03:14

> そういうことは、質問文に書いておいてください。 申し訳ありません、明記しておきます。
kei344

2016/11/22 05:56

回答文に追記しているのですが、御覧になられましたか?
hnkyi

2016/11/22 06:20

返答遅くなり申し訳ございません! 試してみて、JSONがsubmitで送信されるのは確認したのですが、JSONの形式が期待した結果となりませんでした... 期待値:{"hoge": "111", "huga": "222"} 実績値:{"json": {"hoge": "111", "huga": "222"}} // hiddenフィールドのname属性がJSONに入ってきてしまう。Railsの仕様??
kei344

2016/11/22 06:46

json から取り出すのもだめなのですね。では serializeArray は使えませんね。 同じように全要素をそれぞれhiddenで追加すればいいと思いますよ。
kei344

2016/11/22 06:47

ここで回答するとマイナスが付くようですね。残念です。
yambejp

2016/11/22 08:32

なんか思い込みがあってそれに合わないとマイナス評価してくるみたいですね 別に評価を上げてほしいとは思いませんが、回答するだけ無駄なような気がします
guest1213

2016/11/28 00:58

私はマイナスにしました。 どこが悪いか聞いたり、マイナス評価の理由を邪推する前に、この回答のコードをテストして本当にJSONがPOSTできるか確認してみてはいかがでしょうか。
kei344

2016/11/28 05:44

To: guest1213さん 回答されたものを見て、「Content-Type:application/jsonのデータのPOST」だということにやっと思い至りました。なので、「この回答のコードをテストして本当にJSONがPOSTできるか」は確認のしようが有りません。(formのPOSTを受け取ってそれをJSONにすると思っている状態では確認しています)ひとことコメントして欲しかったです。
guest

0

ベストアンサー

サーバー側がContent-Type:application/jsonのデータのPOSTしか受け付けず、かつ結果をContent-Type:text/htmlで返してくる、ということですね。そしてそのHTMLを表示したいと。

この場合、HTMLのformではJSONはPOSTできませんので、実現不可能です。よってAjaxなり、他の方法でJSONをPOSTするしかないのですが、その場合は「画面遷移」が不可能です。

なので私が思いつく案としては受け取ったHTMLで現在のドキュメントの内容を書き換えて「遷移に見せかける」くらいしかありませんが、以下のサンプルのような感じではどうでしょうか。

html

1<!DOCTYPE html> 2<html> 3<head> 4 <meta charset="utf-8"> 5 <title>a</title> 6 <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> 7</head> 8<body> 9 <form action="b.html"> 10 </form> 11 <button id="a">submit</button> 12 <script> 13 var data = {"message": "hello"}; 14 var action = $("form").attr("action"); 15 var forwarded = false; 16 $("#a").on("click", function() { 17 $.ajax({ 18 type: "POST", 19 url: action, 20 dataType: "html", 21 contentType: "application/json", 22 data: JSON.stringify(data), 23 success: function(res) { 24 // レスポンスからDOMを構築してscriptタグだけ復元可能なようにしておく 25 newHtml = new DOMParser().parseFromString(res, "text/html"); 26 var scriptElements = Array.prototype.map.call( 27 newHtml.getElementsByTagName("script"), function(elem) { 28 return elem; 29 } 30 ); 31 var scriptParents = []; 32 var scriptNexts = scriptElements.map(function(elem) { 33 scriptParents.push(elem.parentNode); 34 for(;elem.nextSibling !== null && elem.nextSibling.tagName === "script"; 35 elem = elem.nextSibling) {} 36 return elem.nextSibling; 37 }); 38 var i = 0; 39 for(i = 0; i < scriptParents.length; i++) { 40 scriptParents[i].removeChild(scriptElements[i]); 41 } 42 43 // 現在のドキュメントを空(<html>のみ)にする 44 while(document.documentElement.firstChild) { 45 document.documentElement.removeChild(document.documentElement.firstChild); 46 } 47 // レスポンスのDOMから現在のドキュメントに要素を移動させる 48 while(newHtml.documentElement.firstChild) { 49 document.documentElement.appendChild( 50 newHtml.documentElement.removeChild(newHtml.documentElement.firstChild)); 51 } 52 // scriptの復元 53 var loaded = Promise.resolve(); 54 for(i = 0; i < scriptParents.length; i++) { 55 (function(i) { 56 loaded = loaded.then(function() { 57 return new Promise(function(resolve) { 58 var script = document.createElement("script"); 59 for(var j = 0; j < scriptElements[i].attributes.length; j++) { 60 var attr = scriptElements[i].attributes.item(j); 61 script.setAttribute(attr.name, attr.value); 62 if(attr.name === "src") { 63 // ファイルを読み込んでいる場合は以降のコードは読み込み終わってからでないといけない 64 script.onload = function() { resolve(); }; 65 } 66 } 67 scriptParents[i].insertBefore(script, scriptNexts[i]); 68 script.textContent = scriptElements[i].textContent; 69 if(!script.onload) { resolve(); } 70 }); 71 }); 72 })(i); 73 } 74 75 // 「戻る」対応 76 if(!forwarded) { 77 history.pushState(null, null, action); 78 } 79 window.onpopstate = function(){ 80 location.reload(); 81 }; 82 }, 83 }); 84 }); 85 // 「進む」対応 86 window.onpopstate = function(){ 87 if(location.pathname.endsWith("/" + action)) { 88 forwarded = true; 89 $("#a").click(); 90 } 91 }; 92 </script> 93</body> 94</html>

ブラウザがHTMLを新たに読み込んだ時のように振舞わせるために、「進む」、「戻る」の制御やスクリプトの実行などいろいろやってますが、これでもたぶんなんか考慮は漏れてます。「HTMLの中身全部」というのがなんとなく危険そうです。あくまでサンプルとして考えてください。

また上記コードは私のオリジナルですが、このような手法はSPA(Single Page Application)などを作成する際の一つの方法として名前がついています。「pjax」というキーワードで調べてみてください。

投稿2016/11/22 08:32

guest1213

総合スコア306

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問