$cache[$key] = empty($arr) ? NULL : $arr; return $cache[$key]; } // 门户 获取需要在频道显示的栏目主题数据 function portal_channel_thread($fid) { global $forumlist; if (empty($fid)) return NULL; $orderby = array('tid' => 1); $page = 1; // 遍历所有在频道显示内容的栏目 $category_forumlist = channel_category($fid); $arrlist = array(); $forum_tids = array(); $tidlist = array(); if ($category_forumlist) { foreach ($category_forumlist as &$_forum) { // 频道显示数据 $arrlist['list'][$_forum['fid']] = array( 'fid' => $_forum['fid'], 'name' => $_forum['name'], 'rank' => $_forum['rank'], 'type' => $_forum['type'], 'url' => $_forum['url'], 'channel_new' => $_forum['channel_new'], ); $forum_thread = thread_tid__find(array('fid' => $_forum['fid']), $orderby, $page, $_forum['channel_new'], 'tid', array('tid')); // 最新信息按栏目分组 foreach ($forum_thread as $key => $_thread) { $forum_tids[$key] = $_thread; } unset($forum_thread); } $tidlist += $forum_tids; } unset($category_forumlist); // 获取属性对应的tid集合 list($flaglist, $flagtids) = flag_thread_by_fid($fid); empty($flagtids) || $tidlist += $flagtids; unset($flagtids); // 频道置顶 $stickylist = sticky_list_thread($fid); empty($stickylist) || $tidlist += $stickylist; // 在这之前合并所有二维数组 tid值为键/array('tid值' => tid值) $tidarr = arrlist_values($tidlist, 'tid'); // 在这之前使用$tidarr = array_merge($tidarr, $arr)前合并所有一维数组 tid/array(1,2,3) if (empty($tidarr)) { $arrlist['list'] = isset($arrlist['list']) ? array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid') : array(); return $arrlist; } $tidarr = array_unique($tidarr); $pagesize = count($tidarr); // 遍历获取的所有tid主题 $threadlist = well_thread_find_asc($tidarr, $pagesize); // 遍历时为升序,翻转为降序 $threadlist = array_reverse($threadlist); foreach ($threadlist as &$_thread) { // 各栏目最新内容 isset($forum_tids[$_thread['tid']]) AND $arrlist['list'][$_thread['fid']]['news'][$_thread['tid']] = $_thread; // 全站置顶内容 isset($stickylist[$_thread['tid']]) AND $arrlist['sticky'][$_thread['tid']] = $_thread; // 首页属性主题 if (!empty($flaglist)) { foreach ($flaglist as $key => $val) { if (isset($val['tids']) && in_array($_thread['tid'], $val['tids'])) { $arrlist['flaglist'][$key][array_search($_thread['tid'], $val['tids'])] = $_thread; ksort($arrlist['flaglist'][$key]); $arrlist['flag'][$_thread['tid']] = $_thread; } } } } unset($threadlist); if (isset($arrlist['sticky'])) { $i = 0; foreach ($arrlist['sticky'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flag'])) { $i = 0; foreach ($arrlist['flag'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flaglist'])) { foreach ($arrlist['flaglist'] as &$val) { $i = 0; foreach ($val as &$v) { ++$i; $v['i'] = $i; } } } isset($arrlist['list']) AND $arrlist['list'] = array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid'); return $arrlist; } ?>javascript - Call Library function from html with google.script.run - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Call Library function from html with google.script.run - Stack Overflow

programmeradmin1浏览0评论

I implement library with Google App Script and I have some difficulties to call a function from library using google.script.run.

Here is the code of my Library :

Code.gs

function ShowSideBar() {
    var html = HtmlService.createTemplateFromFile('Index_librairie').evaluate()
        .setTitle('Console de gestion')
        .setWidth(300);
    SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
        .showSidebar(html);
}

function execution_appeler_par_html(){
  Logger.log("execution_appeler_par_html"); 

}

Index_librairie.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
    google.script.run.withSuccessHandler(work_off).execution_appeler_par_html(); 
    function work_off(e){
    alert(e);
    }
    </script>
  </head>
  <body>
    test de ouf
  </body>
</html>

Here is my Spreadsheet that use the Library : Code.gs

function onopen() {
  lbrairietestedouard.ShowSideBar();
}

Google.script.run does not reconize execution_appeler_par_html() function. I should use libraryname.execution_appeler_par_html() but this syntaxe doesn't work in configuration of google.script.run

I implement library with Google App Script and I have some difficulties to call a function from library using google.script.run.

Here is the code of my Library :

Code.gs

function ShowSideBar() {
    var html = HtmlService.createTemplateFromFile('Index_librairie').evaluate()
        .setTitle('Console de gestion')
        .setWidth(300);
    SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
        .showSidebar(html);
}

function execution_appeler_par_html(){
  Logger.log("execution_appeler_par_html"); 

}

Index_librairie.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
    google.script.run.withSuccessHandler(work_off).execution_appeler_par_html(); 
    function work_off(e){
    alert(e);
    }
    </script>
  </head>
  <body>
    test de ouf
  </body>
</html>

Here is my Spreadsheet that use the Library : Code.gs

function onopen() {
  lbrairietestedouard.ShowSideBar();
}

Google.script.run does not reconize execution_appeler_par_html() function. I should use libraryname.execution_appeler_par_html() but this syntaxe doesn't work in configuration of google.script.run

Share Improve this question edited Sep 14, 2023 at 10:20 TheMaster 50.5k7 gold badges69 silver badges98 bronze badges asked Feb 22, 2018 at 13:42 Edouard DelgaEdouard Delga 951 silver badge7 bronze badges 1
  • Have you tired a dummy function, which in turn calls lbrairietestedouard.execution_appeler_par_html(). Ex: function dummy(){ lbrairietestedouard.execution_appeler_par_html() } in your HTML side just call google.script.run.dummy() – Jack Brown Commented Feb 22, 2018 at 16:33
Add a comment  | 

5 Answers 5

Reset to default 14

It seems that google.script.run can't look inside Objects or self-executing anonymous functions. In my case, putting any code inside an object or IIFE resulted in "is not a function" type of error being thrown in the console.

You can work around this by declaring a single function that will call nested methods inside libraries and objects.

.GS file

 function callLibraryFunction(func, args){

    var arr = func.split(".");
    
    var libName = arr[0];
    var libFunc = arr[1];
    
    args = args || [];
       
   return this[libName][libFunc].apply(this, args);

}

In JavaScript, every object behaves like an associative array of key-value pairs, including the global object that 'this' would be pointing to in this scenario. Although both 'libName' and 'libFunc' are of String type, we can still reference them inside the global object by using the above syntax. apply() simply calls the function on 'this', making the result available in global scope.

Here's how you call the library function from the client:

 google.script.run.callLibraryFunction("Library.libraryFunction", [5, 3]);

I don't claim this solution as my own - this is something I saw at Bruce McPherson's website a while back. You could come up with other ad-hoc solutions that may be more appropriate for your case, but I think this one is the most universal.

Noticed the same problem trying to invoque library from google.script.run within HTML code. Here is the workaround I use :

LIBRARY SIDE : aLibrary

function aFunction(){
    //code...;

}

ADDON SIDE (requires library "aLibrary")

function aFunction(){
    aLibrary.aFunction();

}

HTML

<input type="button" value="run aFunction" onclick="google.script.run.aFunction()" />

I like the workaround because I keep a clear view and organisation of my functions names, and do not need to alter HTML code if I bring my functions directly inside the addOn project, once development is satsifying.

Only thing I did not try yet : handling arguments and return values....

I hope this contribution is not to foolish, please forgive me I am very amateur...

After quite long time working on this, I found out that any function that you call from the library using google.script.run must exist in both the main script and the library script. The function must at least be declared in the main script while the implementation as well as the parameters are not important. The implementation will be in your library. If the main script does not include the name of the function, the error <your function> is not a function will appear.

Now that there is no meaning of having a library if every single function needs to exist in the main function, the solution provided by @Anton Dementiev would be used as a workaround. Suppose you have a function named testFunc in your library, you can call it using the following method:

google.script.run.callLibraryFunction("testFunc", [5, 3]);

where the library has this function:

function callLibraryFunction(func, args) {
  args = args || [];
  return this[func].apply(this, args);
}

and the main script has this declaration:

function callLibraryFunction() {

}

Google must fix this stupid behaviour

I have a similar issue which I was directed to this thread for recently, and I tried numerous solutions... however, I came across another thread yesterday (which I unfortunately clicked out of / lost track of so I can't link to it) that had a proposed solution to a different problem I was facing with Libraries.

Angelo's answer on this thread is actually very close to what I found that worked for me, so please refer to his answer with one slight modification on the client-side/add-on side:

function aFunction(){
    return aLibrary.aFunction();
}

For me, simply adding "return" in is what did the trick. This was an extremely simple solution (far more simple than many of the other options suggested) so I thought it'd be valuable to share for anyone else in my boat. It might not work for everyone (I haven't tested it fully yet) but it changed my "null" values to the expected array values that I wanted, so I'm satisfied with it for my simple/amateur needs. Not sure if it'll work with arguments, but at least for simple functions without arguments it gets the job done.

Update: I just tested it with a simple argument array where I updated both Lib/Client sides to accept the argument, set a variable on the client side's html script to var testArray = ['opt 1', 'opt 2', 'opt 3'] and fed it into the function via the html script -- worked perfectly both ways and came out the other side in my html/JavaScript output. So I can confirm it should work even for functions with simple arguments at this point.

The issue, as far as I can tell, is due to hoisting - see this answer here.

The difference is that functionOne is a function expression and so only defined when that line is reached, whereas functionTwo is a function declaration and is defined as soon as its surrounding function or script is executed (due to hoisting).

Evidently, google.script.run executes at a level prior to any variable declarations in dependent scripts. So yes, when using callbacks of the form google.script.run.myWhateverCallback() in a library, dependent scripts must define that callback as a hoistable function and not in a variable/constant declaration.

/* don't do this, as you might for your controller actions in the app menu */
const { myWhateverCallback, myOtherCallback } = MyParentLibrary;

/* do this instead, for *every* callback needed by google.script.run */
function myWhateverCallback()
  MyParentLibrary.myWhateverCallback(...arguments);
}

According to prior answers, the body of the function may be redundant since the final execution of the function is in the scope of the parent library - but I haven't tested this, and Google may yet fix it so I'm using the hoisted callback functions as actual wrappers just in case.

发布评论

评论列表(0)

  1. 暂无评论