Loading custom module base on context in server side SuiteScript 2.0 - lazy-loading

I'm trying to load my custom module base on the condition.
CustomModule.js
define([], function(){
export {
run: function(){ log.debug('run in CustomModule' }
};
}
And here is my user event script
userevent.js
define(['N/record'], function(record){
...
var moduleName = record.getValue('custom_module_name'); // will return CustomModule.js
require([moduleName], function(customModule){
customModule.run();
});
});
But I got following error
{
type: "error.SuiteScriptModuleLoaderError",
name: "INCORRECT_SUITESCRIPT_CONFIGURATION",
message: "Incorrect SuiteScript configuration for module: CustomModule.js",
}
When I using preload like define(['CustomModule.js'), function(customModule){...})
is working, but this might not suitable for our scenario.
Any suggestion?

So the way you would call a custom module would be (sample snippets below):
CustomModule.js [Code in file cabinet]
define([], function() {
// You can have multiple functions
function testFunction() {
log.debug("Run in CustomModule");
return 123;
}
return { // Return all your functions here
testFunction: testFunction
};
});
And the way you would call the custom module functions in other scripts would be:
Sample User Event Script:
/**
* #NApiVersion 2.x
* #NScriptType UserEventScript
* #NModuleScope SameAccount
*/
define(['./CustomModule.js'], function(customModule) {
.....
function sampleFunction(customerId, recId, invNumberCounter) {
var storeNumber = customModule.testFunction(); // value of 'storeNumber' will be 123
}
.....
});
Additional Important Note:
When writing library scripts (custom modules), have the client-side supported modules in a different script and server-side supported modules in a different script.
This is because, if you incorporate a library script that has a module which is supported only by server-side scripts (eg. N/task module) into a client script, an error would be thrown saying that the module is not supported in this scrpt.
Hope this helps.

Related

javascript function is not recognized as javascript code

I have the following javascript file MyService.js:
function(config) {
config.MyService = function(request) {
return call('classpath:path/to/my.feature#tag', request);
};
return config;
}
I load this js from my karate-config.js in order to reuse it from my feature files.
config = karate.callSingle('classpath:path/to/MyService.js', config);
It works as expected and I can call my.feature from any feature file. For example:
Given def res = call MyService myRequest
The problem appears when I try to add a new level to MyService.js function:
function(config) {
config.ApiOauthService = {
myCall : function(request) {
return call('classpath:path/to/my.feature#tag', request);
}
};
return config;
}
When I add the following code to my feature file:
Given def myCall = call MyService.myCall myRequest
I get the following error: "not a js function or feature file"
Do anybody know where is the problem? Is it possible to do what I am trying to do?
Thanks
Yes in Karate 0.9.3 onwards we have limited JS function nesting to only the top-level. You can find a full explanation in this comment.
So if you need JS function "name spacing" you can easily achieve this as per the documentation: https://github.com/intuit/karate#multiple-functions-in-one-file
And if you need more complex nesting, switch to using Java code where you can nest functions at any level.

rollup equivalent of "browserify -r"

I need to force some modules into my bundle, as they are required dynamically through some code like below:
var moduleName = "someModule";
var myModule = require(moduleName);
I was using browserify to bundle this (through browserify -r or the API equivalent).
I am trying to switch to rollup and I don't figure out how to do this with rollup. Basically, I just want to force some modules into the bundle, and make them available globally through the require statement.
I think the key here is to use the new ES6 module syntax as described in the Rollup documentation. This will also give Rollup the possibility to apply features like chunking and tree-shaking.
Another important thing is to make it explicit what might get imported. By that I mean to use statements like 'import('./module1.js')' instead of 'import(some_variable)'. It is hard for Rollup to figure out all possible contents of the variable which gets used in the import. Therefore I would use explicit file names here but wrap everything in some kind of if/else condition.
Consider the following example:
File ./src/main.js:
let num = Math.random() * 10;
let condition = Math.round(num % 3);
let mod;
if (condition === 1) {
import('./module1.js').then((module)=> {
log(module);
});
} else if (condition === 2) {
import('./module2.js').then((module)=> {
log(module);
});
} else {
import('./module3.js').then((module)=> {
log(module);
});
}
function log(module) {
mod = module;
console.log(mod.test());
console.log('Done');
}
File ./src/module1.js:
function test() {
return 'This is 1!';
}
export { test };
The files module2.js and module3.js are the same like module1. The only difference is that they log 'This is 2!' and 'This is 3!'.
The Rollup config looks like this:
const production = !process.env.ROLLUP_WATCH;
export default {
inlineDynamicImports: true,
input: 'src/main.js',
output: {
dir: 'public/',
format: 'esm',
sourcemap: true
}
};
If you run 'rollup -c' then there will be one file './public/main.js'. This bundle will include all three modules. Usually Rollup would create main.js and three chunks. By using the setting 'inlineDynamicImports=true', Rollup puts everything in one file.
You can also change the format in the Rollup config to 'iife' (or amd, cjs, umd) if you want to.

Dexie.js table.name isn't working even though the table is under the tables property

I'm wanting to fetch all items from a table into a collection but am getting an error that the table name is undefined. Here is my store:
db.version(1).stores({
users: '++id,',
orgs: '++id,',
applications: '++id'
})
Then later here is my call:
db.orgs.toCollection().count(function (count) {
console.log(count)
})
It gives the following error:
TypeError: Cannot read property 'toCollection' of undefined
But when I stop the debugger at the call and type in db.tables sure enough:
1:Table {name: "orgs", schema: TableSchema, _tx: undefined, …}
_tx:undefined
hook:function rv(eventName, subscriber) { … }
name:"orgs"
Any help is appreciated - thanks.
UPDATE
I noticed that when I seeded the database on initial creation I could fetch the data out. So I copied in that code into my template. It still fails however, so there must be something simple I'm missing, here is that code:
import Dexie from '#/dexie.es.js'
export default {
name: 'ListOrgs',
data: () => {
return {
orgs: []
}
},
methods: {
populateOrgs: async function () {
let db = await new Dexie('myDatabase').open()
db.orgs.toCollection().count(function (count) {
console.log(count)
})
}
},
mounted () {
this.populateOrgs()
}
}
Dexie has two modes
Static - the most common one used in most samples.
Dynamic - Schema is not specified in code.
Static Mode
//
// Static Mode
//
const db = new Dexie('myDatabase');
db.version(1).stores({myTable1: '++'});
db.version(2).stores({myTable1: '++, foo'});
db.myTable1.add({foo: 'bar'}); // OK - dexie knows about myTable1!
Dynamic Mode
//
// Dynamic Mode
//
const db = new Dexie('myDatabase');
// FAIL: db.myTable1.add({foo: 'bar'}); // myTable1 is unknown to the API.
// Here, you must wait for db to open, and then access tables using db.table() method:
db.open().then(db => {
const myTable = db.table('myTable');
if (myTable) {
myTable.add({foo: 'bar'});
}
}).catch(error => {
console.error(error);
});
If omitting any version() specification, Dexie will just try to open any existing database with the same name, no matter version or schema. But it won't create the implicit table properties onto the db instance.
When Dynamic Mode is Useful
Dynamic mode can be useful when building an arbritary database utility that should adapt to any indexedDB database - such as a DB explorer. Dynamic mode can also be useful when the javascript code is by design not aware of the schema (what tables are expected to be queried and what indexes there are).
Benefits with Static Mode
No need to wait for db.open() to complete.
Automatic DB creation when neeeded. No complex app code to deal with database versioning.
Automatic DB population when needed.
Design Patterns in Static Mode
db.js
import Dexie from 'dexie';
//
// Let this module do several things:
//
// * Create the singleton Dexie instance for your application.
// * Declare it's schema (and version history / migrations)
// * (Populate default data http://dexie.org/docs/Dexie/Dexie.on.populate)
//
export const db = new Dexie('myDatabase');
db.version(1).stores({
users: '++id,',
orgs: '++id,',
applications: '++id'
});
db.on('populate', () => {
return db.orgs.bulkAdd([
{'foo': 'bar'},
]);
});
app.js
import {db} from './db';
// Wherever you use the database, include your own db module
// instead of creating a new Dexie(). This way your code will
// always make sure to create or upgrade your database whichever
// of your modules that comes first in accessing the database.
//
// You will not have to take care of creation or upgrading scenarios.
//
// Let Dexie do that for you instead.
//
async function countOrgs() {
return await db.orgs.count();
}

Define containing a deferred object

About require instruction, Dojo official doc says:
if a configuration object is provided, it is passed to the configuration API as described >in Configuration. Next, the dependencies listed in dependencies (if any) are resolved. >Finally, callback (if any) is executed with the resolved dependencies passed in as >arguments
With my example (below), I want to use users.json data in main program, but callback of the called module (monModule.js) is not executed and I obtain an empty object.
How can I proceed ?
Thanks to you.
1 )Main program (extract)
<script type="text/javascript">
require(["monModule"],function(monModule){
console.log(monModule);// returns {}
});
</script>
2) Called module (monModule.js) :
define(["dojo/request/xhr","dojo/json"],function(xhr,json){
xhr("users.json",{handleAs:"JSON"}).
then(function(data){console.log(return data;});
});
3) users.json
[
{‘ id’:"id1",’nom’:"nom1"},
{ ‘id’:"id2",’nom’:"nom2"},
{‘id’:"id3",’nom’:"nom3"}
]
the call in the then is also async so that is why you are getting back an empty object. you will have to add another deferred to your module for it to run and a then in your code
define( ["dojo/request/xhr","dojo/json" , "dojo/Deferred"], function( xhr, json , deferred) {
var def = new deferred();
xhr("users.json", { handleAs :"JSON" }).then(
function( data ) {
return def.resolve(data);
}
);
return def.promise;;
});
And in Code get it by
require(["custom/monModule"],function(monModule){
monModule.then(function(users){
console.log(users);
});
});

WinJS Enumeration

How can I make an enumeration in WinJS?
I tried to make a class like this for example:
(function () {
"use strict";
var TaskEnum = WinJS.Class.define(
null,
{},
// The set of static members.
{
SUPERVISION: 1,
DIG: 2,
MAP: 3,
});
var Task = new TaskEnum();
WinJS.Namespace.define("ENUMS", {
TASK: {
get: function () {
return Task;
}
}
});
})();
But when I call ENUMS.TASK.DIG then DIG is undefined.
I even tried just this:
WinJS.Namespace.define("ENUMS", {
TASK: { SUPERVISION: 1, DIG: 2, MAP: 3, }
});
But when I call ENUMS.TASK.DIG then DIG is still undefined.
It seems like the Namespace.define does not work in that way?
Ohk, If i get you exact then , you want to define Enumeration in JavaScript?
right ?
For this case I don't think if it is done with WinJs or not on Windows Store App,
but I have two Suggestions as my answer :
1 ) Use C# as Runtime Component to perform This operations, by defining a function in c# and simply call it on your JavaScript.
See ,Creating a simple component in C#.
2 ) Enumerated types in JavaScript
Or See : WinJS.UI Namespace
http://207.46.99.208/pl-pl/library/windows/apps/br229782#enums_section
I might not understand what you're hoping to get out of the Namespace definition, but not just use core JavaScript?
window.ENUMS = {
TASK: {
SUPERVISION: 1,
DIG: 2,
MAP: 3
}
};
Then use it like you were trying to:
callSomeFunction(ENUMS.TASK.DIG);
Note that if you can restrict users to IE11 (not so difficult in Win8 apps) then you can make use of JavaScript constants through const as well.