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

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

ただいまの
回答率

90.53%

  • JavaScript

    19891questions

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

  • HTML

    11130questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

  • HTML5

    4982questions

    HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

  • バリデーション

    52questions

    Validationとは特定の入力データが、求められた条件に当てまっているかをチェックするために使われます。

バリデーションが上手くいかない。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 718

aaaaaaaa

score 467

ブレイクスルーjavascript(SHOEISYA)の22pから32pに記述してある、フォームに書き込まれた内容を即時に検証(文字数や適切な単語が利用されているかなど)でき、
何か問題があれば注意が表示される機能を実際に作るという内容に疑問があったので質問します。
実際に作ってみたものの、動作しません。javascriptソースを確認してみるといくつか誤植があったので修正してみたのですが、それでも動きませんでした。
フォームに文字を入力し、それに何かしらの間違い(文字数が8文字以内かつ、4文字以上、必須項目)を犯せば注意が表示される仕組みなのですが、
その注意が表示されないのです。

function AppModel(attrs) {
    this.val ="";
    //使用するvalidation patternを設定するオブジェクトを追加する。
    this.attrs = {
        required: "",//値が空かどうかを調べるrequiredメソッド。
        maxlength: 8,
        minlength: 4
    };

        this.listeners = {
        valid: [],//valid…正当な、有効な
        invalid: []//invalid…病人
    };
}
//AppModelのプロトタイプたち。つまりインスタンスに継承させたいものだ。

//this.valの値が正しいのかどうかを調べるvalidateメソッド。
AppModel.prototype.validate = function() {
    var val;
    //バリデーションでエラーが出たものを保存しておくための空の配列
    this.errors = [];

          for(var key in this.attrs) {
        val = this.attrs[key];
                if(!this[key](val)) this.errors.push(key);
    }
        this.trigger(!this.errors.length ? "valid" : "invalid");
};

//第一引数に配列の添え字、第二引数に第一引数を処理する関数を指定した。
AppModel.prototype.on = function(event, func) {
    //AppModelがもつ連想配列listeners内の、eventという添え字を持つモノ(恐らく配列だろうが、いまのところeventを添え字に持つ配列は、見当たらない。)の末尾にfuncという関数を挿入している。
    this.listeners[event].push(func);
};

AppModel.prototype.trigger = function(event) {
    $.each(this.listeners[event], function() {
        //コンストラクター内でのthisは、インスタンスを表すので、this()は、AppModel()なのか?
        //▼このthis()の意味は良くわからない。(1/27)
        this();
    });
};
//恐らくセッター。受け取ったvalが、AppModelのthis.valと一致すれば処理を行わない。一致しなければ、this.valに引数を代入する。
AppModel.prototype.set = function(val) {
    if(this.val === val) return;
    this.val = val;
    this.validate();
};

//値が空かどうかを判定するrequiredメソッド。
AppModel.prototype.required = function() {
    return this.val !== "";
};
//値の文字数が引数のnum以上かどうかを判定するmaxlengthメソッド。
AppModel.prototype.maxlength = function(num) {
    return num >= this.val.length;
};
//値の文字数が引数num以下かどうかを判定するminlengthメソッド。
AppModel.prototype.minlength = function(num) {
    return num <= this.val.length;
};


function AppView(el) {

    this.initialize(el);
    //インスタンス化したとき、handleEventsメソッドを実行するようにしている。
    this.handleEvents();
}

AppView.prototype.initialize = function(el) {
    this.$el = $(el);

    //this.$elの隣のliをthis.$listに代入する。
    this.$list = this.$el.next().children();

    var obj = this.$el.data();

    if(this.$el.prop("required")) {
        obj["required"] = "";
    }

        this.model = new AppModel(obj);
};

AppView.prototype.handleEvents = function() {
    var self = this;
    //handleEventsメソッドでは、keyupイベントのイベントハンドラにonKeyupを登録する。
    this.$el.on("keyup", function(e) {
              self.onKeyup(e);
    });

    this.model.on("valid", function() {
        self.onValid();
    });

    this.model.on("invalid", function() {
        self.onInvalid();
    });
};
//keyupイベントが発生した時に実行されるonKeyupメソッドを実装する。
AppView.prototype.onKeyup = function(e) {
    var $taget = $(e.currentTarget);
    //this.modelのsetメソッドを使用して、inputの値をmodelにセットする。$target.valのvalは、requiredやmaxlengthか?
    this.model.set($target.val());
};

//this.$elのclass="error"を消し、this.$listを非表示にする。
AppView.prototype.onValid = function() {
    this.$el.removeClass("error");
    this.$list.hide();
};

//そしてthis.$elにclass="error"を付与し、this.$listの中で該当エラーのみ表示する。
AppView.prototype.onInvalid = function() {
    var self =this;
    this.$el.addClass("error");
    this.$list.hide();

    $.each(this.model.errors, function(index, val) {
        self.$list.filter("[data-error=\"" + val + "\"]").show();
    });
};
//inputを引数で指定した関数で、個別に処理する。
$("input").each(function() {
    new AppView(this);
});
<div class="container">
  <div class="row">
    <div class="col">
      <label for="">権限を作成</label>
    </div>
    <div class="col">
      <input type="text" placeholder="4文字以上、8文字以内で入力して下さい" data-minlength="4" data-maxlength="8" required><!-- requiredは、フォームへの入力や洗濯を必須とする。 -->
      <ul>
        <li data-error="required">必須項目です。</li>
        <li data-error="minlength">4文字以上で入力して下さい。</li>
        <li data-error="maxlength">8文字以内で入力して下さい。</li>
      </ul>
    </div>
  </div><!-- row -->
  <div class="row">
    <div class="col">
      <label for="">権限を作成</label>
    </div>
    <div class="col">
      <input type="text" placeholder="4文字以上、8文字以内で入力して下さい" data-minlength="4" data-maxlength="8" required>
      <ul>
        <li data-error="required">必須項目です。</li>
        <li data-error="minlength">4文字以上で入力して下さい。</li>
        <li data-error="maxlength">8文字以内で入力して下さい。</li>
      </ul>
    </div>
  </div><!-- row -->
</div><!-- container -->

問題のソースコード
http://jsdo.it/rrrrrrrr/e5jz

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • 退会済みユーザー

    2017/02/17 21:14

    複数のユーザーから「やってほしいことだけを記載した丸投げの質問」という意見がありました
    「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。

  • ikedas

    2017/02/18 11:38

    外部のサイトに置いたソースコードはそのうち消えるかもしれません。後で質問を読む人には意味不明になってしまうので、ソースコードも質問の中に書いて下さい。コードを整形する方法はヘルプ https://teratail.com/help を見て下さい。

    キャンセル

  • aaaaaaaa

    2017/02/24 13:11

    ご返答有難うございました。ソースコードを追記しました。

    キャンセル

回答 2

checkベストアンサー

+3

 修正箇所

元の書籍のコードと解説がわかりませんが下記の場所を修正してください。
modelへのハンドラ設定の方法(A)と(B)

  • AppView.prototype.handleEvents
AppView.prototype.handleEvents = function() {
    var self = this;

    this.$el.on("keyup", function(e) {
              self.onKeyup(e);
    });

    // (A) model.listeners.valid にハンドラを登録する
    this.model.listeners.valid.push(function() {
        self.onValid();
    });

    // (B) model.listeners.invalid にハンドラを登録する
    this.model.listeners.invalid.push(function() {
        self.onInvalid();
    });
};
  • AppView.prototype.onKeyup
    質問内のコードでは、以下のvar $tagetvar $targetのタイプミスだと思います。
AppView.prototype.onKeyup = function(e) {
    var $taget = $(e.currentTarget);
    // イベントを発生させたターゲットの値なので入力されている現在の値がval()です
    this.model.set($target.val());
};

 説明

下記の部分のAppModel.prototype.triggerについて補足説明します。

AppModel.prototype.validate = function() {
    var val;
    //バリデーションでエラーが出たものを保存しておくための空の配列
    this.errors = [];

    for(var key in this.attrs) {
        val = this.attrs[key];
        if(!this[key](val)) this.errors.push(key);
    }

    // エラーの有無により、"valid"か、"invalid"の文字列を引数にしてtriggerを呼び出す
    this.trigger(!this.errors.length ? "valid" : "invalid");
};

AppModel.prototype.trigger = function(event) {
    $.each(this.listeners[event], function() {
        this();
    });
};


listenersはobject型なので[event]は、プロパティへのアクセスとなります。
eventの値が"valid"だとすると、this.listeners.validと等価です。
this.listeners.validは配列なので、$.eachで一つづつ処理されます。
この配列の要素は、handleEventsで登録した(A)や(B)のハンドラで、そのまま呼び出せるので、this()となります。

このAppModel.prototype.triggerの処理から、修正箇所としてハンドラの設定方法を修正しています。

  • jqueryの取り込みは下記の方法で行い、実行できることを確認しました。
...
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
...

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/03/01 19:36

    ご回答有難うございます。詳細な回答で大変参考になりました。
    jqueryを取り込んで、誤記である$tagetを$targetにしたところjsdoで無事動作したことを確認しました。ベストアンサーを押したいところですが、一つ質問させてください。

    全く同じソースをローカルホスト(windows7sp1 xampp1.0.0.0 IE11とchrome56.0.2924.87)で試すと全く動作しないのです。ローカルホストのapp.jsには、回答を基に修正したjsdoitと同等のソースと、同じく回答を基に、AppView.prototype.handleEventsメソッドも修正したソースがあるのですが、どちらも動作せず、表示させたい文言が現れません。
    別の回答にてIE11の開発者ツールでエラーが出ない原因としてjavascriptに関する設定が原因であるとの旨がありました。おそらくPCの内部的な事情で上手くいかないのだと思うのです。
    唯一の手がかりは、クロームの開発者ツールでコンソール画面をみてみると

    GET http://localhost/image/error.png 404 (Not Found)
    (anonymous) @ jquery-1.11.1.min.js:2
    j @ jquery-1.11.1.min.js:2
    fireWith @ jquery-1.11.1.min.js:2
    ready @ jquery-1.11.1.min.js:2
    J @ jquery-1.11.1.min.js:2

    と表示されていました。code.jquery.com/jquery-1.11.1.min.jsは、存在しているのですが何が原因でこうなってしまうのでしょうか。

    キャンセル

  • 2017/03/02 01:37 編集

    app.jsを<head>内で読み込んでいますが、このタイミングではinput要素がまだ生成されていないので要素とコードが関連付きません。

    jsdo.itでjavascript枠に入力したコードは内部で<body>の最後に呼ばれるようになっているので上手く動作します。

    対応するには、input要素が生成された後にイベントを関連付けします。

    (1) app.js側で対応するならばreadyイベントで実行されるようにします。
    ----------javascript : app.js
    // あまり短縮しないで書いた場合
    $(document).ready(function() {
    $("input").each(function() {
    new AppView(this);
    });
    });
    ----------

    (2) html側で対応するならば<head>内からapp.jsの読み込み部分を<body>の末尾へ移動します。
    ---------- html : index.html
    ...
    <script type="text/javascript" src="./app.js"></script>
    </body>
    </html>
    ----------

    コメント欄だとコードが装飾できないようなので少し見辛いです・・・

    キャンセル

  • 2017/03/02 19:37

    ご回答有難うございます。仰るとおりにbody最下部においてファイル読み込みをしたところ、ローカルホスト側でも無事うまくいきました。

    >>app.jsを<head>内で読み込んでいますが、このタイミングではinput要素がまだ生成されていないので要素とコードが関連付きません。
    「どこで知った?」と言われると答えに窮してしまい申し訳ありませんが、今までの認識だと、<head>内で記述した<script src="./a.js">は、<body>配下より先に読み込まれるので問題なく動作するものだと思っておったのです。が、どうも何かと勘違いしているようですが、何と勘違いしているのでしょうか。

    >>jsdo.itでjavascript枠に入力したコードは内部で<body>の最後に呼ばれるようになっているので上手く動作します。
    なるほど、そのような仕様になっているのですね。とても勉強になります。

    >>(1)app.hs側で...のソースは、$(function() {...});と同じもので、画像を除いたすべてのDOMが読み込まれてから…というものでしょうか。ソースを提示して下さるまで忘れてました。情けない限りです。

    キャンセル

  • 2017/03/03 01:06

    最近のteratailの質問で以下のようなものがあります。

    ・scriptタグはなんで通常bodyに書くのか
    https://teratail.com/questions/67208

    回答がいっぱいで色々理由があるのかなぁと。

    SEOとかは除いて、コードについて考えると、
    1. 使う前に関数・変数が定義・宣言されている事
    2. 扱う対象(DOM)が扱う時に存在している事
    を意識すればよいと思います。

    昔、<head>内の<script>が多かったのは、jQueryのようにDOMを検索して編集するのではなく、<xxx onClick="abc();">のようにイベントのハンドラなどを属性へ直接記述していたからかも、、、でも真相はわかりません。
    この場合は、abc()がxxxタグより前で定義されている必要があります。

    キャンセル

+1

$ が定義されていないから。エラー文が出ていると思いますよ。

デベロッパーツールで確認してみてください。⇒ http://eng-entrance.com/javascript-display-error

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/24 19:33

    ご回答有難うございます。
    このような作業を行うときは、できるだけF12で表示される開発者ツールを表示するようにしているのですが、特にエラーはでていませんでした。以下の画面は、動作しないバリデーデーションプログラムを開発者ツールで見てみたものです。もちろんF5を押したあとの画面になっています。
    http://fast-uploader.com/file/7043487567797/

    >>$
    つまりJquery本体のファイルが必要だということですよね。以下のように、グーグル、本家、ダウンロードしたjqueryファイルから呼び出して使ってみたのですが、結局動作しませんでした。
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js&quot;&gt;&lt;/script&gt;
    <script src="http://code.jquery.com/jquery-1.11.1.min.js&quot;&gt;&lt;/script&gt;
    <script type="text/javascript" src"./jquery-1.11.1.js"></script>

    キャンセル

  • 2017/02/24 20:55

    http://jsdo.it/rrrrrrrr/e5jz をWin7 IE11 で開き、jsdo.itの再生ボタンを押すことで開発者ツールにてエラーを確認しました。

    IEでローカルのJavaScriptを実行しようとすると、セキュリティの設定次第だと思いますが実行されないことがあったように記憶しています。なので、スクリプトの実行テスト(勉強)は Firefox がお勧めです。

    キャンセル

同じタグがついた質問を見る

  • JavaScript

    19891questions

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

  • HTML

    11130questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

  • HTML5

    4982questions

    HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

  • バリデーション

    52questions

    Validationとは特定の入力データが、求められた条件に当てまっているかをチェックするために使われます。