functionの戻り値がundefinedになる。

現在タイムカードのアプリを作成しており、退勤ボタン打刻時に位置情報を取得し住所に変換したものを「退勤時住所」フィールドへ更新したいと思っているのですが、住所取得用の関数の戻り値がどうしてもundefinedになってしまいます。。

初歩的な質問だと思うのですが、困っております。

何処がおかしいのかどうかご教授頂けましたら幸いです。

 

(function() {
'use strict';

// Google Map の指定
var script = document.createElement('script');
script.src = 'https://maps.googleapis.com/maps/api/js?key=APIKEY';
document.body.appendChild(script);

// GOOGLE MAP API位置情報取得して住所を入力
function addressGoogle() {

// Geolocation APIに対応しているブラウザ
if (navigator.geolocation){

// 位置を取得する
navigator.geolocation.getCurrentPosition(successFunc, errorCallback, optionObj) ;

} else {
alert('非対応ブラウザ');
}

// 位置取得成功時の処理
function successFunc(position){
// 緯度経度を取得
var latlng = {lat: parseFloat(position.coords.latitude), lng: parseFloat(position.coords.longitude)};
// ジオコーダのコンストラクタ
var geocoder = new google.maps.Geocoder();
// Reverse Geocoding開始
geocoder.geocode({
// 緯度経度を指定
latLng: latlng
}, function(results, status){
// 成功
if (status == google.maps.GeocoderStatus.OK && results[0].geometry) {

var address = results[0].formatted_address;
return address;
}
});
}

// 緯度経度取得失敗時コールバック関数
function errorCallback(error) {
var errMsg = '';
switch (error.code) {
case 0:
errMsg = '原因不明のエラーが発生しました';
break;
case 1:
errMsg = '位置情報の利用が許可されていません';
break;
case 2:
errMsg = '電波状況などで位置情報が取得できませんでした';
break;
case 3:
errMsg = '位置情報の取得に時間がかかり過ぎてタイムアウトしました';
break;
}
alert(errMsg);
}

// オプション・オブジェクト
var optionObj = {
"enableHighAccuracy": false ,
"timeout": 8000 ,
"maximumAge": 5000 ,
};



}


// 緯度経度を取得し、当該レコードを更新
function getPosition(event) {
var appId, recordId, out_time, tanmatu, address;
address = addressGoogle();
if (event.type === 'app.record.detail.show') {
// PC用
appId = kintone.app.getId();
recordId = kintone.app.record.getId();
out_time = moment().format('HH:mm');
tanmatu = 'PC';
} else if (event.type === 'mobile.app.record.detail.show') {
// スマホ用
appId = kintone.mobile.app.getId();
recordId = kintone.mobile.app.record.getId();
out_time = moment().format('HH:mm');
tanmatu = 'mobile';
}
var objParam = {
app: appId,
id: recordId,
record: {
退勤時住所: {
value: address
},
退勤時間: {
value : out_time
},
退勤時間更新端末: {
value : tanmatu
}
}
};
// レコードを更新
kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', objParam, function() {
// 成功時は画面をリロード
location.reload(true);
}, function(resp) {
// エラー時はメッセージを表示して、処理を中断
alert('error->' + resp);
return;
});

}


// 緯度経度を再取得するための(ボタンを配置する)関数
function updatePosition(event) {
var check = document.getElementsByName('update');
if (check.length === 0) {
var button = document.createElement('button');
button.appendChild(document.createTextNode('退勤時間打刻'));
button.setAttribute('name', 'update');

var span = document.createElement('span');
span.appendChild(button);

// ボタンを配置するスペースを取得
var elButtonSpace;
if (event.type === 'app.record.detail.show') {
// PC用
elButtonSpace = kintone.app.record.getHeaderMenuSpaceElement();
} else if (event.type === 'mobile.app.record.detail.show') {
// スマホ用
elButtonSpace = kintone.mobile.app.getHeaderSpaceElement();
}
elButtonSpace.appendChild(span);

button.addEventListener('click', function() {
getPosition(event);
});
}
}
// タイムカード新規作成時の動作
function createShow(event) {
var rec = event.record;
//入力す不可にする項目
rec['出勤時間'].disabled = true;
rec['退勤時間'].disabled = true;
rec['出勤時間更新端末'].disabled = true;
rec['退勤時間更新端末'].disabled = true;
rec['集計用'].disabled = true;
rec['lat_0'].disabled = true;
rec['lng_0'].disabled = true;
rec['lat'].disabled = true;
rec['lng'].disabled = true;
rec['出勤時間']['value'] = moment().format('HH:mm');
//var appId, recordId, out_time, tanmatu;
//PCで打刻かモバイルで打刻かの判断
if (event.type === 'app.record.create.show') {
// PC用
rec['出勤時間更新端末']['value'] = 'PC';
//appId = kintone.app.getId();
//recordId = kintone.app.record.getId();

} else if (event.type === 'mobile.app.record.create.show') {
// スマホ用
rec['出勤時間更新端末']['value'] = 'mobile';
//appId = kintone.mobile.app.getId();
//recordId = kintone.mobile.app.record.getId();
}
return event;
}

// タイムカード編集時の動作
function editShow(event) {
var rec = event.record;
rec['出勤時間'].disabled = true;
rec['退勤時間'].disabled = true;
rec['出勤時間更新端末'].disabled = true;
rec['退勤時間更新端末'].disabled = true;
rec['集計用'].disabled = true;
rec['lat_0'].disabled = true;
rec['lng_0'].disabled = true;
rec['lat'].disabled = true;
rec['lng'].disabled = true;
return event;
}
kintone.events.on(['app.record.detail.show', 'mobile.app.record.detail.show'], updatePosition);
kintone.events.on(['app.record.create.show', 'mobile.app.record.create.show'], createShow);
kintone.events.on(['app.record.edit.show', 'mobile.app.record.edit.show'], editShow);

})();

> 住所取得用の関数

 

どの関数名でしょうか?

すみません!肝心の関数名が抜けていました。

addressGoogle()となります。

あー

> // 位置を取得する
> navigator.geolocation.getCurrentPosition(successFunc, errorCallback, optionObj) ;

これが非同期なんですよね、、なので下記のようにPromiseを使えばやりたいことはできるとおもいます。

https://qiita.com/makotoyc/items/aee473b341cd3a7bd31f

村濱一樹様

ありがとうございます!

無事動作しました。

不格好かもしれませんが動作したコードを置いておきます。

本当にありがとうございました!

 

(function() {
'use strict';

// Google Map の指定
var script = document.createElement('script');
script.src = 'https://maps.googleapis.com/maps/api/js?key=APIKEY';
document.body.appendChild(script);

// GOOGLE MAP API位置情報取得して住所を入力
function addressGoogle() {
return new Promise(function(resolve, reject) {

// Geolocation APIに対応しているブラウザ
if (navigator.geolocation){
// 位置を取得する
navigator.geolocation.getCurrentPosition(
(position) => {
// 緯度経度を取得
var latlng = {lat: parseFloat(position.coords.latitude), lng: parseFloat(position.coords.longitude)};
// ジオコーダのコンストラクタ
var geocoder = new google.maps.Geocoder();
// Reverse Geocoding開始
geocoder.geocode({
// 緯度経度を指定
latLng: latlng
}, function(results, status){
// 成功
if (status == google.maps.GeocoderStatus.OK && results[0].geometry) {

var address = results[0].formatted_address;
resolve(address);
}
});
},
// 取得失敗した場合
(error) => {
switch (error.code) {
case 1: //PERMISSION_DENIED
alert("位置情報の利用が許可されていません");
break;
case 2: //POSITION_UNAVAILABLE
alert("現在位置が取得できませんでした");
break;
case 3: //TIMEOUT
alert("タイムアウトになりました");
break;
default:
alert("その他のエラー(エラーコード:" + error.code + ")");
break;
}
reject(error.code);
},

// [第3引数] オプション
{
"enableHighAccuracy": false,
"timeout": 8000,
"maximumAge": 2000,
}




);
//navigator.geolocation.getCurrentPosition(successFunc, errorCallback, optionObj) ;

} else {
alert('非対応ブラウザ');
}

});
}



// 緯度経度を取得し、当該レコードを更新
function getPosition(event) {
var appId, recordId, out_time, tanmatu, address;

addressGoogle().then(value => {
address = value;
if (event.type === 'app.record.detail.show') {
// PC用
appId = kintone.app.getId();
recordId = kintone.app.record.getId();
out_time = moment().format('HH:mm');
tanmatu = 'PC';
} else if (event.type === 'mobile.app.record.detail.show') {
// スマホ用
appId = kintone.mobile.app.getId();
recordId = kintone.mobile.app.record.getId();
out_time = moment().format('HH:mm');
tanmatu = 'mobile';
}
var objParam = {
app: appId,
id: recordId,
record: {
退勤時住所: {
value: address
},
退勤時間: {
value : out_time
},
退勤時間更新端末: {
value : tanmatu
}
}
};
// レコードを更新
kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', objParam, function() {
// 成功時は画面をリロード
location.reload(true);
}, function(resp) {
// エラー時はメッセージを表示して、処理を中断
alert('error->' + resp);
return;
});
});

}


// 緯度経度を再取得するための(ボタンを配置する)関数
function updatePosition(event) {
var check = document.getElementsByName('update');
if (check.length === 0) {
var button = document.createElement('button');
button.appendChild(document.createTextNode('退勤時間打刻'));
button.setAttribute('name', 'update');

var span = document.createElement('span');
span.appendChild(button);

// ボタンを配置するスペースを取得
var elButtonSpace;
if (event.type === 'app.record.detail.show') {
// PC用
elButtonSpace = kintone.app.record.getHeaderMenuSpaceElement();
} else if (event.type === 'mobile.app.record.detail.show') {
// スマホ用
elButtonSpace = kintone.mobile.app.getHeaderSpaceElement();
}
elButtonSpace.appendChild(span);

button.addEventListener('click', function() {
getPosition(event);
});
}
}
// タイムカード新規作成時の動作
function createShow(event) {
var rec = event.record;
//入力す不可にする項目
rec['出勤時間'].disabled = true;
rec['退勤時間'].disabled = true;
rec['出勤時間更新端末'].disabled = true;
rec['退勤時間更新端末'].disabled = true;
rec['集計用'].disabled = true;
rec['lat_0'].disabled = true;
rec['lng_0'].disabled = true;
rec['lat'].disabled = true;
rec['lng'].disabled = true;
rec['出勤時間']['value'] = moment().format('HH:mm');
//var appId, recordId, out_time, tanmatu;
//PCで打刻かモバイルで打刻かの判断
if (event.type === 'app.record.create.show') {
// PC用
rec['出勤時間更新端末']['value'] = 'PC';
//appId = kintone.app.getId();
//recordId = kintone.app.record.getId();

} else if (event.type === 'mobile.app.record.create.show') {
// スマホ用
rec['出勤時間更新端末']['value'] = 'mobile';
//appId = kintone.mobile.app.getId();
//recordId = kintone.mobile.app.record.getId();
}
return event;
}

// タイムカード編集時の動作
function editShow(event) {
var rec = event.record;
rec['出勤時間'].disabled = true;
rec['退勤時間'].disabled = true;
rec['出勤時間更新端末'].disabled = true;
rec['退勤時間更新端末'].disabled = true;
rec['集計用'].disabled = true;
rec['lat_0'].disabled = true;
rec['lng_0'].disabled = true;
rec['lat'].disabled = true;
rec['lng'].disabled = true;
return event;
}
kintone.events.on(['app.record.detail.show', 'mobile.app.record.detail.show'], updatePosition);
kintone.events.on(['app.record.create.show', 'mobile.app.record.create.show'], createShow);
kintone.events.on(['app.record.edit.show', 'mobile.app.record.edit.show'], editShow);

})();

意図する動作になったならよかったです!! :+1:

お世話になっております。

昨日から少し書き方を変えたりなど試してみたのですが、promiseの構造がよくわからず迷走しております。。

行いたいことはポータルに出勤・退勤のボタンを設置し、それぞれボタンクリック時にレコードを作成または更新するといった形です。

今現在レコード作成はされるのですが、住所が入力されません。

昨日と同じくpromiseが原因だとは思うのですが、複数組み合わせるための記述方法がわからずお助けいただけないでしょうか。

わからないところはGET・POSTにpromiseがいるのかどうかといる場合、addressGoogle(option)の関数を使用したpromiseの組み合わせ方です。

addressGoogle(option)の戻り値も本当は文字列で返してほしいのですが、スマートな戻り値の受け取り方もあまり理解できておらずわからないことだらけです。

どうぞよろしくお願い致します。

 

(function() {
'use strict';

// Google Map の指定
var script = document.createElement('script');
script.src = 'https://maps.googleapis.com/maps/api/js?key=APIKEY';
document.body.appendChild(script);

function buttonPortal(event) {
var el;

var option = {
"enableHighAccuracy": false,
"timeout": 8000 ,
"maximumAge": 2000 ,
} ;

if(event.type == "portal.show"){ // PC用

el = kintone.portal.getContentSpaceElement();

// 出勤ボタン作成
var clockInButton = document.createElement('button');
clockInButton.textContent = '出 勤';
clockInButton.style.margin = '5px 0 0 16px';
clockInButton.onclick = function() {
// 出勤の処理
alert('出勤ボタンを押しました');
// タイムカード本日のレコードあるかチェック
var params = {
app: 128,
query: "作成日時 = TODAY() and 作成者 in (LOGINUSER())"
};
return kintone.api(kintone.api.url('/k/v1/records'), 'GET', params).then(function(resp) {
alert(resp.records[0]);
if (resp.records[0] !== undefined) {
alert('本日打刻済みです!');
}else{
alert('本日ない場合');
var time, tanmatu, address;
time = moment().format('HH:mm');
addressGoogle(option).then(value => {
address = value;
if (event.type === 'portal.show') {
// PC用
tanmatu = 'PC';
} else if (event.type === 'mobile.portal.show') {
// スマホ用
tanmatu = 'mobile';
}
var objParam = {
app: 128,
record: {
出勤時住所: {
value: address
},
出勤時間: {
value : time
},
出勤時間更新端末: {
value : tanmatu
}
}
};
// レコードを更新
return kintone.api(kintone.api.url('/k/v1/record', true), 'POST', objParam).then(function() {
// 成功時は画面をリロード
location.reload(true);
}, function(resp) {
// エラー時はメッセージを表示して、処理を中断
alert('error->' + resp);
return;
});
});

}
console.log(RecordId);
return RecordId;
});
};
el.appendChild(clockInButton);
}
}else if(event.type == "mobile.portal.show"){
//モバイルの場合の処理書く
}

// GOOGLE MAP API位置情報取得して住所を入力
function addressGoogle(options) {
// Geolocation APIに対応しているブラウザ
if (navigator.geolocation){
return new Promise(function(resolve, reject) {
// 位置を取得する
navigator.geolocation.getCurrentPosition(resolve, reject, options)
}).then(function(position) {
// 緯度経度を取得
var latlng = {lat: parseFloat(position.coords.latitude), lng: parseFloat(position.coords.longitude)};
// ジオコーダのコンストラクタ
var geocoder = new google.maps.Geocoder();
// Reverse Geocoding開始
geocoder.geocode({
// 緯度経度を指定
latLng: latlng
}, function(results, status){
// 成功
if (status == google.maps.GeocoderStatus.OK && results[0].geometry) {

var address = results[0].formatted_address;
resolve(address);
}
});
}).catch(function(error) {
switch (error.code) {
case 1: //PERMISSION_DENIED
alert("位置情報の利用が許可されていません");
break;
case 2: //POSITION_UNAVAILABLE
alert("現在位置が取得できませんでした");
break;
case 3: //TIMEOUT
alert("タイムアウトになりました");
break;
default:
alert("その他のエラー(エラーコード:" + error.code + ")");
break;
}
reject(error.code);
});

} else {
alert('非対応ブラウザ');
}
}


// タイムカード編集時の動作
function editShow(event) {
var rec = event.record;
rec['出勤時間'].disabled = true;
rec['退勤時間'].disabled = true;
rec['出勤時間更新端末'].disabled = true;
rec['退勤時間更新端末'].disabled = true;
rec['集計用'].disabled = true;
rec['lat_0'].disabled = true;
rec['lng_0'].disabled = true;
rec['lat'].disabled = true;
rec['lng'].disabled = true;
return event;
}
kintone.events.on(['app.record.edit.show', 'mobile.app.record.edit.show'], editShow);
kintone.events.on(['portal.show', 'mobile.portal.show'], buttonPortal);

})();

https://developer.cybozu.io/hc/ja/articles/360023047852-kintone%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8BPromise%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%AE%E5%9F%BA%E6%9C%AC

 

Promiseについてはこちらに詳しくまとめておりますので、こちらを真似てみれますでしょうか?

 

> Promiseをつかって同期処理をする(複数)

 

が参考になると思います。

 

前回よりPromiseを検索し続け未だにきちんとは理解は出来ていませんが、なんとか自分の希望の動作をさせることが出来ました。

ありがとうございました。

Promiseの概念むずかしいですよね、わからないことがあればお答えしますので気軽にご質問ください!