How load functions with same name - javascript

I'm developing by Openui5 a portal. My portal have 2 apps. I I have organized the code in folders:
root
|
|____app1
|____app2
In app1 folder I have util1.js with a function getInfo() and in app2 folter I have util2.js with function getInfo() (same name).
Now my portal, at root login, load all js files in all subfolders, and only the last loaded getInfo() function work (correct???)
I think in the future to dynamically load the js file of appX only when the user enter in the appX.
In this way it work correctly??

Don't make your getInfo functions global. (This would be good advice even if you only had one of them, the global namespace is very crowded.)
Instead, ideally, have a single global for your portal's apps, perhaps called Apps, which is an object. Then have each app add itself to that object as a property, using the app's name. So:
portal.js:
var Apps = {};
app1.js:
Apps.App1 = {
getInfo: function() {
// ...
},
somethingElse: function() {
// ...
}
// ...and so on...
};
app2.js:
Apps.App2 = {
getInfo: function() {
// ...
},
somethingElse: function() {
// ...
}
// ...and so on...
};
Or you might go further and have an app registration function:
portal.js:
var MyPortal = {
apps: {},
register: function(name, app) {
if (this.apps.hasOwnProperty(name)) {
throw new Error("There is already an app called '" + name + "' registered.");
}
this.apps[name] = app;
}
};
app1.js:
MyPortal.register("App1", {
getInfo: function() {
// ...
},
somethingElse: function() {
// ...
}
// ...and so on...
});
app2.js:
MyPortal.registerApp("App2", {
getInfo: function() {
// ...
},
somethingElse: function() {
// ...
}
// ...and so on...
});

Related

cannot override mixin behavior after it's used in a class definition

I need to override some member functions added by a mixin from a 3rd-party library. The problem is: the mixin is used in multiple 3rd-party class definitions immediately, in the same script file where the mixin is defined. And I can only insert custom code before or after this script, but not in between. If I call override afterwards, then already defined classes don't obtain my function in the call chain.
// library script BEGIN
Ext.define('Foo.bar.Base', {
});
Ext.define('Foo.bar.Util', {
newmember: function() {
console.log('newmember');
}
});
Ext.define('Foo.bar.Derived', {
extend: 'Foo.bar.Base',
mixins: {
fooutil: 'Foo.bar.Util'
}
});
// library script END
Foo.bar.Util.override({
newmember: function () {
console.log('newmember2');
this.callParent();
}
});
var obj = new Foo.bar.Derived();
obj.newmember();
Actual Output:
newmember
Desired Output:
newmember2
newmember
Override before defining a class using a mixin. This can be done using override as a property when defining:
Ext.define('Foo.bar.UtilOverride',{
override: 'Foo.bar.Util',
newmember: function () {
console.log('newmember2');
this.callParent();
}
});
// library script BEGIN
Ext.define('Foo.bar.Base', {
});
Ext.define('Foo.bar.Util', {
newmember: function() {
console.log('newmember');
}
});
Ext.define('Foo.bar.Derived', {
extend: 'Foo.bar.Base',
mixins: {
fooutil: 'Foo.bar.Util'
}
});
// library script END
var obj = new Foo.bar.Derived();
obj.newmember();

Intern js :How to return PageObject of the page from the function which opens it ?

I'm working on a UI automation project using Intern js . And I'm implementing it using page object model . I have a simple scenario where user enters credentials in login page and is navigated to welcome page.
In my script i have a 'doLogin()' function in LoginPage which is responsible for entering credentials and clicking submit button.
Now the problem is i want doLogin() to return WelcomePage and i'm unable to figure out the way to do this.
Heres my code setUp:
LoginPage.js
define([],
function () {
function LoginPage(remote) {
this.remote = remote;
}
LoginPage.prototype = {
constructor: LoginPage,
// Login Page related Methods
doLogin: function(username,password){
this
.findById(json.locators.username).
.type(username).end()
.findById(json.locators.password)
.type(username).end()
.findByXpath(json.locators.sumit).click().end()
.sleep(1000).then(function(){
return welcomePage// this is not working
})
}
};
return LoginPage;
});
WelcomePage.js
define([],
function () {
function WelcomePage(remote) {
this.remote = remote;
}
WelcomePage.prototype = {
constructor: WelcomePage,
doSomething: function(){
//welcome page related method
}
};
return WelcomePage;
});
Now what i actually want to achive is to do something like:
loginpage.doLogin(usrname,password).doSomething();
can somebody help on this??
A more flexible way to implement page objects is to make them groups of helper functions (like Leadfoot's pollUntil) rather than Command-like objects.
Using that model, your LoginPage object might look like:
define([], function () {
return {
doLogin: function (username, password) {
return function () {
return this.parent
.findById(json.locators.username).
.type(username).end()
.findById(json.locators.password)
.type(username).end()
.findByXpath(json.locators.sumit).click().end()
.sleep(1000).then(function(){
return welcomePage// this is not working
});
}
}
};
});
WelcomePage might look like
define([], function () {
return {
doSomething: function () {
return function () {
return this.parent
// more stuff
}
}
};
});
You can call this.parent in the returned function because when the helper function is called (as a Command then callback) it's context will be set to the Command that's calling it.
You would use them like
define([
'./WelcomePage',
'./LoginPage',
// ...
], function (
welcomePage,
loginPage,
// ...
) {
// ...
this.remote
.get('some page')
.then(loginPage.doLogin('username', 'password'))
.then(welcomePage.doSomething())
// other stuff
// ...
});

page object: visit <page_url> in nightwatch.js

In Geb and WATIR there are certain keywords which we use to visit to the page_url which we have specified in page class. E.g. to keyword in Geb and visit keyword in WATIR.
What similar we can use in nightwatch.js. This is what I have tried but it gives error:
I have tried:
module.exports = {
url: function () {
return this.api.globals.launchUrl + "/goto/desiredPage.html";
},
commands: [pageCommands],
elements: {}
};
In page class I am using it as:
desiredPage
.url()
.foo()
.bar();
client.end();
but it is giving error .url is not a function.
You can see the nightwatch examples inside the nightwatch folder for example:
[page-objects/home.js]
var searchCommands = {
submit: function() {
this.waitForElementVisible('#submitButton', 3000)
.click('#submitButton')
.api.pause(1000);
return this; // Return page object for chaining
}
};
module.exports = {
url: 'http://google.com',
commands: [searchCommands],
elements: {
searchBar: { selector: 'input[name=q]' },
submitButton: { selector: 'button[type=submit]' }
}
};
and then in the test:
/* jshint expr: true */
module.exports = {
'Demo Google search test using page objects' : function (client) {
var homePage = client.page.home();
homePage.navigate();
homePage.expect.element('#searchBar').to.be.enabled;
homePage
.setValue('#searchBar', 'Nightwatch.js')
.submit();
var resultsPage = client.page.searchResults();
resultsPage.expect.element('#results').to.be.present.after(2000);
resultsPage.expect.element('#results').to.contain.text('Nightwatch.js');
resultsPage.expect.section('#menu').to.be.visible;
var menuSection = resultsPage.section.menu;
menuSection.expect.element('#web').to.be.visible;
menuSection.expect.element('#video').to.be.visible;
menuSection.expect.element('#images').to.be.visible;
menuSection.expect.element('#shopping').to.be.visible;
menuSection.productIsSelected('#web', function(result) {
this.assert.ok(result, 'Web results are shown by default on search results page');
});
client.end();
}
};
so "url()" command in pages does not exist you need to define the url in te page and the use "navigate()" instead.

ember-cli data returned empty using initializer

I have an app where we need to create an initializer that inject our global into all the route where our global is a function that load data from a JSON file and return the data.
global-variable.js
export function initialize(container, application) {
var systemSetting = {
systemJSON: function(){
return Ember.$.getJSON("system/system.json").then(function(data){
return data
});
}.property()
};
application.register('systemSetting:main', systemSetting, {instantiate: false});
application.inject('route', 'systemSetting', 'systemSetting:main');
}
export default {
name: 'global-variable',
initialize: initialize
};
index.js - route
export default Ember.Route.extend({
activate: function(){
var _settings = self.systemSetting.systemJSON;
console.log(_settings.test);
},
}
system.JSON
{
"test" : 100
}
the result of the console.log give me this
ComputedProperty {isDescriptor: true, _dependentKeys: Array[0], _suspended: undefined, _meta: undefined, _cacheable: true…}
I think it's because of the JSON is not loaded yet but after that I try to do something like this at route
index.js - route
activate: function(){
var self = this;
var run = Ember.run
run.later(function() {
var _settings = self.systemSetting.systemJSON;
console.log(_settings);
}, 1000);
},
but still give me the same log. Am I use wrong approach to this problem?
I finally found the answer. Because of what I want to call is from an initializer then one that I must do is to use .get and if I just using get then the one that I received is a promise and to get the actual data I must use .then
The code will look like this:
index.js - route
activate: function(){
this.get('systemSetting.systemJSON').then(function(data) {
console.log(data.test);
});
}

Async loading a module property

I've defined a module (module1) which is supposed to load the value of a property asynchronously. How can I use this property in my app as soon as it is defined and only after it is defined?
My setup (simplified)
v1
app.js
require(['module1'], function(mod) {
document.getElementById("greeting").value = mod.getPersonName();
});
module1.js
define(['jquery'], function($) {
_person;
$.get('values/person.json')
.done(function(data) {
_person = data
});
return {
getPersonName: function() { return _person.name; }
}
values/person.json
{ name: 'John Doe', age: 34 }
This only works if the GET happens nearly instantaneously, otherwise it fails because _person is undefined when getPersonName is called.
v2
To counter this, I figured I would register a callback to notify the app when person was loaded.
app.js
require(['module1'], function(mod) {
mod.onPersonLoaded(function() {
document.getElementById("greeting").value = mod.getPersonName();
});
});
module1.js
define(['jquery'], function($) {
_person;
_onLoaded;
$.get('values/person.json')
.done(function(data) {
_person = data;
_onLoaded();
});
return {
getPersonName: function() { return _person.name; },
onPersonLoaded: function(cb) { _onLoaded = cb; }
}
}
This works if the GET is slow, however, if it's quick _onLoaded is undefined when .done() is called.
Is there a good way to use _person values in app.js as soon as they are defined and only once they are defined?
I'm using RequireJS, but my question is generally applicable to AMD.
Edit
In simplifying my example, I removed a layer which may be important. I'm using RactiveJS for the UI.
Setup (slightly less simplified)
app.js
require(['Ractive', 'module1'], function(Ractive, mod) {
var ractive = new Ractive({
...
data : {
name: mod.getPersonName()
}
});
ractive.observe(...);
ractive.on(...);
});
Edit 2
My current solution, subject to change. Register a callback that notifies app.js when person is loaded. Callback is called immediately if person is already loaded when callback is registered.
app.js
require(['Ractive', 'module1'], function(Ractive, mod) {
var ractive = new Ractive({
...
data : {}
});
mod.watchPerson(function() {
ractive.set('person.name', mod.getPersonName());
});
ractive.observe(...);
ractive.on(...);
});
module1.js
define(['jquery'], function($) {
_person;
_onLoaded;
$.get('values/person.json')
.done(function(data) {
_person = data;
try {
_onLoaded();
} catch (e) {
// that was fast!
// callback will be called when it is registered
});
return {
getPersonName: function() { return _person.name; },
watchPerson: function(cb) {
_onLoaded = cb;
if(_person != null) {
_onLoaded();
}
}
}
}
Promises are a good choice here because callbacks are always called asynchronously - you never encounter that confusing situation where _onLoaded() gets called before it's designed.
Unfortunately, jQuery's promise implementation doesn't adhere to the Promises/A+ specification, so you don't get that guarantee. If possible, you could use an alternative AJAX library like Reqwest, and do something like
app.js
define(['module1'], function (mod) {
mod.then(function(person) {
// do something with person.name
}
});
module1.js
define(['reqwest'], function (reqwest) {
return reqwest('values/person.json');
});
Using the text loader plugin
Another option, since you're already using AMD, would be to use a loader plugin, such as text:
app.js
define(['module1'], function (person) {
// do something with person.name
});
module1.js
define(['text!values/person.json'], function (personJSON) {
return JSON.parse(personJSON);
});
Using the text loader plugin
In fact there's even a JSON plugin, so you could do away with module1 entirely in this example situation:
app.js
define(['json!values/person'], function (person) {
// do something with person.name
});
This is how I would do this. Basically, it is not much different from your V2, but it adds more incapsulation.
app.js
require(['module1'], function(mod) {
mod.loadPerson(function(person) {
document.getElementById("greeting").value = person.getPersonName();
});
});
module1.js
define(['jquery'], function($) {
return {
loadPerson : function(callback) {
$.get('values/person.json').done(function(data) {
_person = data;
callback({
getPersonName: function() { return _person.name; }
});
});
}
}
}
You may also use promises promises instead of simple callback.

Categories