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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Haml

Haml(HTML abstraction markup language)は、HTML/XHTMLを効率的に記述するためのマークアップ言語および記法です。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

JavaScript

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

Q&A

解決済

4回答

1508閲覧

[JS]DOMContentLoadedイベントを起こしたところ関数が参照できなくなりました。

norun07

総合スコア8

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Haml

Haml(HTML abstraction markup language)は、HTML/XHTMLを効率的に記述するためのマークアップ言語および記法です。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

JavaScript

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

0グッド

0クリップ

投稿2020/01/31 07:58

app/assets/javascripts/main.js内

js

1window.addEventListener('DOMContentLoaded', function(){ 2 // Option 3 var CLIENT_ID = 'xxxxxxxxxxxxxxxxxxxxxxxx'; 4 var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest"]; 5 6 var SCOPES = "https://www.googleapis.com/auth/youtube.readonly"; 7 8 var authorizeButton = document.getElementById('authorize-button'); 9 var signoutButton = document.getElementById('signout-button'); 10 var content = document.getElementById('content'); 11 var channelForm = document.getElementById('channel-form'); 12 var channelInput = document.getElementById('channel-input'); 13 var videoContainer = document.getElementById('video-container'); 14 var defaultChannel = 'techguyweb'; 15 16 // Form submit and change channel 17 channelForm.addEventListener('submit', function(e){ 18 e.preventDefault(); 19 20 var channel = channelInput.value; 21 22 getChannel(channel); 23 }); 24 25 26 // Load auth2 libraly 27 function handleClientLoad(){ 28 gapi.load('client:auth2' , initClient); 29 } 30 31 // Init API client library and set up sign in listeners 32 function initClient(){ 33 gapi.client.init({ 34 discoveryDocs: DISCOVERY_DOCS, 35 clientId: CLIENT_ID, 36 scope: SCOPES 37 }).then(() => { 38 //Listen for sign in state changes 39 gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus); 40 // Handle initial sign in state 41 updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get()); 42 authorizeButton.onclick = handleAuthClick; 43 signoutButton.onclick = handleSignoutClick; 44 }); 45 } 46 47 // Update UI sign in state changes 48 function updateSigninStatus(isSignedIn) { 49 if(isSignedIn){ 50 authorizeButton.style.display = 'none'; 51 signoutButton.style.display = 'block'; 52 content.style.display = 'block'; 53 videoContainer.style.display = 'block'; 54 getChannel(defaultChannel); 55 } else { 56 authorizeButton.style.display = 'block'; 57 signoutButton.style.display = 'none'; 58 content.style.display = 'nonek'; 59 videoContainer.style.display = 'none'; 60 } 61 } 62 63 // handle login 64 function handleAuthClick(){ 65 gapi.auth2.getAuthInstance().signIn(); 66 } 67 68 // handle logout 69 function handleSignoutClick(){ 70 gapi.auth2.getAuthInstance().signOut(); 71 } 72 73 // Display channel data 74 function showChannelData(data){ 75 var channelData = document.getElementById('channel-data'); 76 channelData.innerHTML = data; 77 } 78 79 // Add commas to number 80 function numberWithCommas(x) { 81 return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); 82 } 83 84 85 86 // Get channel from API 87 function getChannel(channel){ 88 gapi.client.youtube.channels 89 .list({ 90 part: 'snippet,contentDetails,statistics', 91 forUsername: channel 92 }) 93 .then(response => { 94 console.log(response); 95 var channel = response.result.items[0]; 96 97 var output = ` 98 <ul class='collection'> 99 <li class='collection-item'>Title: ${channel.snippet.title}</li> 100 <li class='collection-item'>ID: ${channel.id}</li> 101 <li class='collection-item'> Subscribers: ${ 102 numberWithCommas(channel.statistics.subscriberCount) 103 }</li> 104 <li class='collection-item'>Views: ${ 105 numberWithCommas(channel.statistics.viewCount) 106 }</li> 107 <li class='collection-item'>Videos: ${ 108 numberWithCommas(channel.statistics.videoCount) 109 }</li> 110 </ul> 111 <p>${channel.snippet.description}</p> 112 <hr> 113 <a class='btn grey darken-2' target='_blank' href="https://youtube.com/${channel.snippet.customUrl}"> 114 Visit Channel</a> 115 `; 116 showChannelData(output); 117 118 var playlistId = channel.contentDetails.relatedPlaylists.uploads; 119 requestVideoPlaylist(playlistId); 120 }) 121 .catch(error => alert('No Channel By That Name')); 122 } 123 124 function requestVideoPlaylist(playlistId){ 125 var requestOptions = { 126 playlistId: playlistId, 127 part: 'snippet', 128 maxResults: 10 129 } 130 131 var request = gapi.client.youtube.playlistItem.list(requestOptions); 132 133 request.execute(response => { 134 console.log(reaponse); 135 var playListItems = response.result.items; 136 if(playListItems){ 137 var output = '<h4 class="align-center">Latest Videos</h4>'; 138 139 // Loop through videos and append output 140 playListItems.forEach(item => { 141 var videoId = item.snippet.resourceId.videoId; 142 143 output += ` 144 <div class="col s3"> 145 <iframe width="100%" height="auto" src="https://www.youtube.com/embed/ 146 ${videoId}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> 147 </div> 148 `; 149 }); 150 151 // Output videos 152 videoContainer.innerHTML = output; 153 154 } else { 155 videoContainer.innerHTML = 'No Uploaded Videos'; 156 } 157 }); 158 } 159}); 160

大変、記述が助長になってしまい申し訳ございません。
より詳細に分析して頂きたいのでよろしくお願い致します。
Uncaught ReferenceError: handleClientLoad is not defined
at HTMLScriptElement.onload
というエラーが出ており、
function handleClientLoad(){
gapi.load('client:auth2' , initClient);
}
こちらの関数が参照できません。
youtubeのチャンネル名をフォーム内に記述するとその結果がhtmlとして表示されると言うものです。
一応、googleアカウントでログインがされると検索フォームが現れるという仕様になっております。

haml

1%section 2 .container 3 %p Log in With Google 4 %button.btn.red#authorize-button 5 Log in 6 %button.btn.red#signout-button 7 Log Out 8 %br/ 9 #content 10 .row 11 .col.s6 12 %form#channel-form 13 .input-field.col.s6 14 %input#channel-input{:placeholder => "Enter Channel Name", :type => "text"} 15 %input.btn.grey.lighten-2#submits__btn{:type => "submit", :value => "Get Channel Data"} 16 .col.s6#channel-data 17 .row#video-container 18%script{:src => "/assets/main.js"} 19 20%script{:async => "https://apis.google.com/js/api.js", :defer => " https://apis.google.com/js/api.js", :onload => "this.onload=function(){};handleClientLoad()", :onreadystatechange => "if (this.readyState === 'complete') this.onload()", :src => "https://apis.google.com/js/api.js"}

元々、DOMContentLoadedイベントをjs全体に記述する前は、channelForm.addEventListener('submit' function(e){})の部分でchannelFormのオブジェクトがnullというエラーが出ておりました。

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

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

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

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

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

guest

回答4

0

functionは一式、window.addEventListenerのスコープ外においてください

投稿2020/01/31 08:09

yambejp

総合スコア114572

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

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

norun07

2020/01/31 08:33

回答誠にありがとうございます。 変数はスコープ内に置いてそれ以外はスコープ外ということでしょうか? やってみましたがエラーが出てしまいました。。
yambejp

2020/01/31 08:35

> 変数はスコープ内に置いてそれ以外はスコープ外 いえ、function xxx(){・・・} というユーザー関数を宣言しているものをスコープ外です。 それ以外のプログラムのながれはスコープ内です
norun07

2020/01/31 08:41

そのようにやり直したところ スコープ内で定義している変数がスコープ外の関数内でその変数が定義されていない事になりました。 main.js:35 Uncaught ReferenceError: DISCOVERY_DOCS is not defined このようなエラーが出てしまいました。
norun07

2020/01/31 08:44

window.addEventListener('DOMContentLoaded', function(){ // Option var CLIENT_ID = 'xxxxxxxxxx'; var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest"]; var SCOPES = "https://www.googleapis.com/auth/youtube.readonly"; var authorizeButton = document.getElementById('authorize-button'); var signoutButton = document.getElementById('signout-button'); var content = document.getElementById('content'); var channelForm = document.getElementById('channel-form'); var channelInput = document.getElementById('channel-input'); var videoContainer = document.getElementById('video-container'); var submitButton = document.getElementById('submits__btn'); var defaultChannel = 'techguyweb'; // Form submit and change channel channelForm.addEventListener('submit', function(e){ e.preventDefault(); var channel = channelInput.value; getChannel(channel); }); }); channelForm.addEventListener これをスコープ内に入れると var channelForm = document.getElementById('channel-form'); var channelInput = document.getElementById('channel-input'); これらは参照可能なようです。
yambejp

2020/01/31 08:47 編集

> スコープ外の関数内でその変数が定義されていない事になりました。 おっと、よく読んでませんでした。 引数で渡さずに直接参照なのですね?それはちょっとひどくないですか? 変数は引数で渡して、値を引き継ぐ場合は戻り値で戻すような 書き方が肝要です どうしても無理なら、クラスで処理するか(それでも書き方は変わります) グローバル変数の宣言をするか・・・どんどんヒドイ書き方になっていく 感は否めませんが・・・
norun07

2020/01/31 08:47

関数の引数の中に使用する変数を記述すれば良いですか? スコープの中はこちらで宜しいでしょうか。
norun07

2020/01/31 08:47

ご丁寧にありがとうございます。
yambejp

2020/01/31 08:47

> 関数の引数の中に使用する変数を記述すれば良いですか? 関数を呼ぶときに引数で渡すことも忘れずに
norun07

2020/01/31 08:49

承知いたしました。 channelForm.addEventListener('submit', function(e){ e.preventDefault(); var channel = channelInput.value; getChannel(channel); }); こちらはスコープ内に置いたままで宜しいでしょうか?
yambejp

2020/01/31 09:21

channelInputが同じスコープ内で宣言されているのでなんとか なりそうな気はしますけど、なんともいえません。 addEventListenerのコールバックには外部から変数を もっていきづらいですね。 bindしたりプロパティで渡してe.targetから参照するとか やりようはありますが・・・
m.ts10806

2020/01/31 09:34

いったんRubyのHaml離れて静的HTMLからの操作にしたほうが良さそう。
guest

0

ベストアンサー

こちらの関数が参照できません。

はい、関数内に書いた以上、関数にローカルなものとなりますので、外側に置いた<script>からの参照はできなくなります。

いちばん簡便には、https://apis.google.com/js/api.jsについてはasyncdeferによる遅延を諦めて、application.jsより先にロードを行って、DOMContentLoadedの中で直接gapi.load('client:auth2' , initClient);を実行する方法が考えられます。

投稿2020/01/31 08:13

maisumakun

総合スコア145121

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

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

norun07

2020/01/31 08:37

application.jsより先にロードを行うのはどのようにすれば宜しいでしょうか。 調べましたが中々できませんでした。 DOMContentLoadedはfunction handleClientLoadこの関数のみ記述すればようのでしょうか? 申し訳ございません。
maisumakun

2020/01/31 08:52

> application.jsより先にロードを行うのはどのようにすれば宜しいでしょうか。 api.jsを読み込む<script>タグをapplication.jsの読み込み行より上に持っていって、asyncやdefer属性を外してください。
norun07

2020/01/31 09:00

すみません application.jsの読み込み行がどこなのかわかりません。_ _
maisumakun

2020/01/31 09:02

layoutの中です(以前の質問で上がっていたかと思います)。
norun07

2020/01/31 09:09

%head %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/ %title Tube = csrf_meta_tags = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %script{:onload => "this.onload=function(){};handleClientLoad()", :onreadystatechange => "if (this.readyState === 'complete') this.onload()", :src => "https://apis.google.com/js/api.js"} = javascript_include_tag 'application', 'data-turbolinks-track': 'reload' このように記述いたしました。 ですが、 VM981 :23 Uncaught ReferenceError: handleClientLoad is not definedこのエラーが出てしまいます。
guest

0

とりあえずその関数だけ動けばよいのであれば。

js

1 // Load auth2 libraly 2 function handleClientLoad(){ 3 gapi.load('client:auth2' , initClient); 4 } 5```6```js 7 // Load auth2 libraly 8 window.handleClientLoad = function (){ 9 gapi.load('client:auth2' , initClient); 10 }

投稿2020/01/31 08:12

kei344

総合スコア69364

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

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

maisumakun

2020/01/31 08:15

handleClientLoadをセットするのがDOMContentLoadedの中だと、タイミング的に<script>のonLoadのほうが先に動いてしまう事故が起きないか、ちょっと木になります。
kei344

2020/01/31 08:20

To: maisumakunさん そうですね、キャッシュされることも考えると結構事故がおきそうですね。
norun07

2020/01/31 08:34

回答ありがとうございます。 ご指示通りに対応いたしましたが次はchannelForm.addEventListener('submit', function(e) こちらのオブジェクトが空と言われました。
guest

0

js

1document.addEventListener("DOMContentLoaded", function(){ 2 document.getElementById('channel-form').addEventListener('submit', function(e){ 3 e.preventDefault(); 4 5 var channel = channelInput.value; 6 7 getChannel(channel); 8 }); 9}, false);

このように記述したところコンソールにエラーは表示され無くなりました。

投稿2020/02/01 05:23

norun07

総合スコア8

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問