I'm developing a sapui5 application. I had in index.html one js file, data.js, where I have const:
const a = 'x';
In index.html, I imported the script:
<scrip src="resources/data.js">
In my onInit() function of main.controller.js I can do this:
var myvar = a; (a is "x")
I created successfully component-preload to improve performance.
I delete the import of data.js from index.html, because I can see in chrome devtool debugger my const a defined in data.js by this way, in component-preloaded.js data.js module:
"mynamespace/resources/data.js":"minify content of data.js";
This works! I can use functions of data.js successfully, but in main.controller.js:
var myvar = a;
I get an exception, "reference not found, a is not defined," same exception in all consts, vars and objects.
What is the problem? Why is a not defined by this way?
Is it necessary do something more in component.js or manifest.json to my const a have been defined in all my controller's?
Thanks.
You have a few options.
Through the individual definitions:
First one, that seems to match your original idea the most is include it by adding it to the require call of your component / controllers / custom controls. You'll probably have to return an object instead of simply declaring the variables though, since it avoids global scope.
sap.ui.define([
"sap/ui/core/UIComponent",
"mynamespace/resources/data"
], function(UIComponent, myData) {
"use strict";
//use the content of myData any way you like
return UIComponent.extend("mynamespace.Component", {
};
};
I recommend sticking it in a JSON model so you can use it as binding as well. If you want to use a JSON model you have several other options.
The first is to create the JSON model with reference to your file. Generally you'd do this in your component file.
new JSONModel("relative/path/to/data")
Through manifest.json
Two ways, one as a file, one without an additional file
"models": {
"mydata": {
"type": "sap.ui.model.json.JSONModel",
"uri": "path/to/data.json",
}
}
If you don't want to load a separate file through ajax, you can add your predefined data as a model in the manifest as well. Take this snippet:
"models": {
"mydata": {
"type": "sap.ui.model.json.JSONModel",
"settings": {
"myvar": "a"
}
}
}
That'll create a JSON model containing whatever is inside the settings bit, so in this case it'll create a model called mydata that has an object with a member called myvar with value a, meaning you can pick it up using the usual model syntax:
this.getOwnerComponent().getModel('mydata').getProperty('/myvar');
.. or use it in your view's bindings
"{mydata>/myvar}"
I tend to use the last option, as it does not load an extra file, and all apps already have a manifest.
I will do it as you said next time I need global const. Thank you.
To solve what I already had wrong, I have minified and compressed all my js files with problems in a single file, and I call it from the index as it worked with data.js.
<script src="/resources/allinone.js"></script>
I know this isn't the best practise but translate all my const of all files to json would take me a long time.
Related
Basically what I need to do is to get a config file from a csv file and load it as an array into a global variable each time I am running tests in before function.
Lets say mynightwatch.conf.js contains following, example global variable myGlobalArr
"globals": {
myGlobalArr : []
}
And in globals.js I am using readFileSync to read a file and get it's text as an array to a variable
before: function(done) {
var file = fs.readFileSync('path').toString().split('\n')
}
How can I pass an array which is stored in file to myGlobalArr and then call it from inside a Page Object to use it?
Thanks
Basically i have two .js files ,let it is A.js and B.js and i have code like this
A.js
function details(age,address,name){
//some code
//some code
getData(age);
//some code
}
function getData(ag){
return ag;
}
B.js
here how can i access that getData(?) ??? , i don't want to use global variable and i just want to know is it possible in any way or choosing global variable is last option.
Until now, plain JavaScript doesn't provide a built-in namespace management for JS resources.
Recently, import feature appeared.
The import statement is used to import functions, objects, or
primitives which are defined in and exported by an external module,
script, or the like.
But beware :
This feature is only just beginning to be implemented in browsers
natively at this time. It is implemented in many transpilers, such as
the Traceur Compiler, Babel, Rollup, and Webpack.
In A.js, you could export getData() as clients need it :
function details(age,address,name){
//some code
//some code
getData(age);
//some code
}
export function getData(ag){
return ag;
}
and in the client code could import it :
import { getData} from '/modules/A.js';
getData(...);
If you want to keep plain JS fully supported, a classic workaround used by the authors of JS libraries is using a single global variable that holds all public resources that the client needs.
In this way, you reduce the risk to have conflict with other libraries or client resources.
If you can change the code of these files, you could define a single global variable :
var myNameSpace = {
details : function(age,address,name){
//some code
//some code
getData(age);
//some code
},
getData : function getData(ag){
return ag;
}
....
};
And access to the function by prefixing with the single global variable : myNameSpace.
myNameSpace.getData(...);
In your A.js file store the returning data that is ag in local/session storage.
You can access this data in B.js which will be in local/session storage.
localStorage.setItem("key", "value");
I have a strange issue with Dust.js contexts. Previously, I would pass the view model along as a plain old JavaScript object, e.g. res.render('page', { something: [1,2,3] } etc. When doing that, I could access something on the local context with {#something}...{/something} etc.
However, I changed the way I manage the context to use dust.makeBase, so that I can have globals and some sort of stack, rather than just an object. I'm using consolidate with express FWIW.
Now, I create the baseViewModel.
//
// at application init
//
app.baseViewModel = dust.makeBase({
someGlobal: 'example'
})
Later on, when rendering, I may extend it like so:
//
// in route handler
//
const viewModel = app.baseViewModel.push({
collection: someCollection
})
res.render('index', viewModel)
But then, the context stack looks like this:
{
"settings": {
// snip
},
"stack": {
"isObject": true,
"head": {
"collection": [
// snip
]
}
},
"global": {
"someGlobal": "example"
}
}
The problem is, now, to access collection, I must prefix the variables with stack.head.:
{#stack.head.collection}
<!-- etc -->
{/stack.head.collection}
Does anyone know why this is, and how I can get back to the simple way of just referring to {#collection} etc?
Thank you.
I managed to get this working, but it's a hack and should have to be done this way. There is a GitHub ticket now for this issue:
https://github.com/linkedin/dustjs/issues/743
Anyway, this is what I did:
dust.helpers.collection = (chunk, context, bodies, params) => {
return context.current().get('collection')
}
And then modified my markup to:
{#collection}
{.Name} etc
{/collection}
Strange, but I guess that's the way it works!
As per our comment chain, here's what I suspect to be the issue.
When you create a new Context object in Dust, it checks to see if you're passing in an existing Context to hydrate from. This is done using an instanceof check.
If the object does not seem to be an instance of a Context, it gets wrapped in a new Context, which would account for the behavior you're seeing here. This isn't great, so I'll go work on a PR to use a flag instead of an instanceof check.
You're using consolidate, which includes a dependency on dust, and I suspect that the version it includes is different than whatever you depend on in your package.json. I would check to see how many copies of dustjs-linkedin are in your tree (one in your root and one in consolidate's node_modules, perhaps). If you require dustjs-helpers it simply requires dustjs-linkedin itself, so the latter is what you really care about.
So here is my problem :
Currently, I have a dozen of functions related to WEBRTC within a template js file. My objective is to have those functions in a separate file, called webRTCWrapper.js for example, and to call those functions in my template without using global variable.
I think I must use namespaces, am I correct ?
If so, how do you use them ?
EDIT : For anyone interested, this is exactly what I was looking for :
http://themeteorchef.com/snippets/using-the-module-pattern-with-meteor/
Make a directory called packages/ parallel to your .meteor/ directory. You can create a package that exports a single object/function. On the command line, use meteor create --package <yourpackagename> and meteor add <yourpackagename> You can edit the js file to add a namespace.
MyNamespace = {};
MyNamespace.myFunction = function () { };
Then, in the package.js, simply export that namespace.
api.export('MyNamespace');
You can use a common pattern of having a global object and your functions inside that object.
Greetings = {
hello: function(name) { return "Hello "+name+" how are you?"; }
}
And then you can call it inside the template helpers :
Template.GreetingsTemplate.helpers({
sayHello: function() { return Greetings.hello('Maxence'); }
})
Take note of the loading order of files in Meteor, anything inside the lib folders is loaded first. If you run into problems where "Greetings" object is not defined, then its because that file was not loaded already.
Edit:
You can reuse the same pattern for adding more functions in different files (you could use App = App || {} but it will throw error in Chrome for example).
App = (typeof App === 'undefined')? {} : App;
App.someFunction = function(){};
or even, if you use underscore.js:
App = (typeof App === 'undefined')? {} : App;
_.extend(App, {
someFunction: function(){}
});
Since now the regular way to use the code from another file was going through a global (server and client). As Joao suggested you can make your own global App variable where you will store or more generically a global MODULE one (basically the same solution as Joao but with explanation).
But with with the arrival of ES2015 support, we will very soon be able to have an official pattern to achieve this. However as the 1.2 does not supports yet the import/export syntax:
Note, The ES2015 module syntax (import/export) is not supported yet in Meteor 1.2.
If you want to start using those features earlier, I would recommend using this package which is an temporary solution to fill the current import/export gap, the meteor team development are currently looking for an elegant solution to support this.
Coming from Java/C# I struggle to understand what that actually means for me as a developer (I'm thinking too much object-oriented).
Suppose there are two html files that use the same Dojo module via require() in a script tag like so:
<script type="text/javascript">
require(["some/module"],
function(someModule) {
...
}
);
</script>
I understand that require() loads all the given modules before calling the callback method. But, is the module loaded for each and every require() where it is defined? So in the sample above is some/module loaded once and then shared between the two HTMLs or is it loaded twice (i.e. loaded for every require where it is listed in the requirements list)?
If the module is loaded only once, can I share information between the two callbacks then? In case it is loaded twice, how can I share information between those two callbacks then?
The official documentation says "The global function define allows you to register a module with the loader. ". Does that mean that defines are something like static classes/methods?
If you load the module twice in the same window, it will only load the module once and return the same object when you request it a second time.
So, if you're having two seperate pages, then it will have two windows which will mean that it will load the module two times. If you want to share information, you will have to store it somewhere (the web is stateless), you could use a back-end service + database, or you could use the HTML5 localStorage API or the IndexedDB (for example).
If you don't want that, you can always use single page applications. This means that you will load multiple pages in one window using JavaScript (asynchronous pages).
About your last question... with define() you define modules. A module can be a simple object (which would be similar to static classes since you don't have to instantiate), but a module can also be a prototype, which means you will be able to create instances, for example:
define([], function() {
return {
"foo": function() {
console.log("bar");
}
};
});
This will return the same single object every time you need it. You can see it as a static class or a singleton. If you require it twice, then it will return the same object.
However, you could also write something like this:
define([], function() {
return function() {
this.foo = function() {
console.log("bar");
};
};
});
Which means that you're returning a prototype. Using it requires you to instantiate it, for example:
require(["my/Module"], function(Module) {
new Module().foo();
});
Prototyping is a basic feature of JavaScript, but in Dojo there's a module that does that for you, called dojo/_base/declare. You will often see things like this:
define(["dojo/_base/declare"], function(declare) {
return declare([], {
foo: function() {
console.log("bar");
}
});
});
In this case, you will have to load it similarly to a prototype (using the new keyword).
You can find a demo of all this on Plunker.
You might ask, how can you tell the difference between a singleton/static class module, and a prototypal module... well, there's a common naming convention to it. When your module starts with a capital letter (for example dijit/layout/ContentPane, dojo/dnd/Moveable, ...) then it usually means the module requires instances. When the module starts with a lowercase letter, it's a static class/singleton (for example dojo/_base/declare, dijit/registry)
1) dojo require, loads the module once and then if you called it again require() will simply return if the package is already loaded. so the request will be called once and it will also call any dependencies once.
but all that if you are in the same HTML page if you leave the page and call the same module in a different page then it will be called from the server. you can also use cache in your config settings so things will be cached in the browser and the file will or not by setting the cacheBust to true if you want a fresh copy or false if you want things to be cached.
2) if you are in the same html page and domain, the module didn't change the module will be the same and you can share values and any change you make you can get it from anywhere unless you call a new instance. but that is not possible between different html pages.
3) not it is not like a static classes or methods from what I understand static methods A static class can be used as a convenient container for sets of methods that just operate on input parameters and do not have to get or set any internal instance fields..
dojo work differently it is a reference for an object if you did it in that way :
define(function(){
var privateValue = 0;
return {
increment: function(){
privateValue++;
},
decrement: function(){
privateValue--;
},
getValue: function(){
return privateValue;
}
};
});
This means every bit of code loads that module will reference the same object in memory so the value will be the same through out the use of that module.
of course that is my understanding please feel free to tell me where I am wrong.