normally i would use this to load dependency
main: function() {
require(['views/home'], function(HomeView) {
_pageView.render(HomeView);
});
}
but now am looking of simplifying it by doing this
main: function() {
require(['views/home'], this.homeView);
},
homeView: function(HomeView) {
this.page = _pageView.render(HomeView);
}
but the keyword this is unrecognizable. How to make it recognizable.
Calling require like this:
require(['views/home'], this.homeView.bind(this));
should prevent this from getting set to a different value when RequireJS calls the callback.
Related
I created a Ext.Mixin component and would like to call a function of it from another component. How do I have to do that? Must be very obvious, but I can't see right now.
EDIT:
Ext.define('ABC.mixin.MyMixin', {
extend: 'Ext.Mixin',
mixinConfig: {
after: {
},
before: {
initComponent: 'init'
}
},
init: function () {
let me = this;
myfunction();
},
myfunction: function () {
//do stuff
}
}
How do I call myfunction() ?
When you include a mixin to a component all of the functions the mixin provides are included to the component itself.
So when you have a reference to your created component you cann call the function on the component itself.
Ext.define('ABC.mixin.MyMixin', {
extend: 'Ext.Mixin',
myfunction: function () {
//do stuff
}
});
Ext.define('ABC.view.MyView', {
mixins: ['ABC.mixin.MyMixin'],
// ...other config stuff
});
let myView = Ext.create('ABC.view.MyView'); // concreate Object of the class ABC.view.MyView
myView.myfunction(); // we can call the function of the mixin on the Object directly.
For more information see the ExtJs documentation
The API Docs seem to provide the information you need. You just include your mixin in the component you need, like so:
Ext.define('ABC.view.MyComponent', {
mixins: ['ABC.mixin.MyMixin'],
initComponent() {
this.myfunction();
this.callParent();
}
});
And from the component's scope, call the mixin's functions you need
I have a problem with implementing Page Object in Nightwatch. Let's say that I have a login scenario. I need to scroll to the element - I'm using for thar execute function.
module.exports = {
'Login' : function (browser) {
browser.url(this.launchUrl)
.setValue('input[name=username]', 'admin')
.setValue('input[name=password]', 'password')
.execute(function () {
document.querySelector('input[type=submit]').scrollIntoView();
}, [])
.click('input[type=submit]');
browser.end();
}
}
I'd like to refactor this login code into Page Object like that
module.exports = {
url: function() {
return this.api.launchUrl;
},
commands: [scrolling],
elements: {
usernameField: {
selector: 'input[name=username]'
},
passwordField: {
selector: 'input[name=password]'
},
submit: {
selector: 'input[type=submit]'
}
}
};
I'd like to 'hide' also this execute command and pack it into commands, like that:
var scrolling = {
scroll: function(){
return this.execute(function () {
document.querySelector(input[type=submit]').scrollIntoView();
}, []);
}
};
Unfortunately it seems that execute command doesn't work with Page Object.
How I can overcome this issue with executing JavaScript code when I want to use Page Object? How can I encapsulate it?
The answer was very simple
1) There was a quotation mark missing in a selector.
2) Using execute() in Object Pattern it is needed to run it using this.api :
this.api.execute(function () {
document.querySelector('input[type=submit]').scrollIntoView();
}, []);
Found the answer
ForthStCheck:function(){
this.api.execute('scrollTo(0,500)')
this.waitForElementVisible('#forthStationPlayBtn',5000)
}
I have a listener setup in my componentDidMount:
updateBasketTotal: function() {
BasketService.getBasketTotal(function(data){
this.setState({
selectedPeopleCount: data.TotalMembers
});
}.bind(this));
},
componentDidMount: function() {
this.updateBasketTotal();
this.subscribeToChannel(basketChannel,"selectAll",this.listenerSelectAll);
this.subscribeToChannel(basketChannel,"removePersonFromBasket",this.listenerRemovePersonFromBasket);
this.subscribeToChannel(basketChannel,"addPersonToBasket",this.listenerAddPersonToBasket);
this.subscribeToChannel(basketChannel,"addArrayToBasket",this.listenerAddArrayToBasket);
},
listenerAddArrayToBasket: function(data){
BasketService.addPerson(data.arrayToPush,function(){
this.updateBasketTotal();
});
},
listenerAddPersonToBasket: function(data){
BasketService.addPerson(data.personId,function(){
this.updateBasketTotal();
});
},
listenerRemovePersonFromBasket: function(data){
BasketService.removePerson(data.personId,function(){
this.updateBasketTotal();
});
},
listenerSelectAll: function(data){
BasketService.selectAll(data.selectAll, function () {
this.updateBasketTotal();
});
}
However, if I publish a message when I'm not on this page, I get an error:
this.updateBasketTotal is not a function
Can anyone please tell me how I can use this.updateBasketTotal?
I think its a problem with 'this' but not sure how to fix it. Thanks in advance
UPDATE:
Have tried adding bind() to the listener:
listenerAddPersonToBasket: function(data){
BasketService.addPerson(data.personId,function(){
this.updateBasketTotal();
}.bind());
},
But no joy, any ideas?
I assume your component is unsubscribing to those channels in componentWillUnmount to avoid resource leaks and duplicate subscriptions.
The asynchronous callbacks should call isMounted to ensure the component is still mounted before attempting anything else.
BasketService.selectAll(data.selectAll, function () {
if (this.isMounted()) {
this.updateBasketTotal();
}
}.bind(this));
I don't know if the isMounted check will solve your problem since that may also not be a function anymore. If it isn't, you might consider adding your own property to track whether the component is mounted or not and check that rather calling a function.
listenerAddArrayToBasket: function(data) {
var _this = this;
BasketService.addPerson(data.arrayToPush,function() {
_this.updateBasketTotal();
});
}
or
listenerAddArrayToBasket: function(data) {
BasketService.addPerson(data.arrayToPush,function() {
this.updateBasketTotal();
}.bind(this));
}
React does not bind context by default, you have to do it yourself. In your example this would refer to callback function, not to react object.
You can either assign react context to a variable and use it inside your callback, or bind context directly to callback.
Here is the great article explaining contexts in JavaScript
Also in ES6 it's possible to use double arrow declaration
class SomeComponent extends React.Component {
updateBasketTotal() {
....
}
lisneterAddArrayToBasket() {
BasketService.addPerson(data.arrayToPush, () => {
this.updateBasketTotal()
})
}
}
You can use babel to compile your ES6 code to old plain ES5 :)
I am facing a weird issue in a requirejs/backbonejs application. I have a Globals.js file which returns reusable utilities. It looks something like this.
define(
['newapp/routers/index', 'newapp/controllers/index', 'newapp/utilities'],
function(Router, Controller, Utilities) {
return {
router: new Router({controller: Controller}),
utilities: Utilities,
navigate: function(path, opts) {
this.router.navigate('app/' + path, opts);
}
}
})
When I require this module in modules that return Backbone Views, it is able to resolve Globals to an object and call methods on it. However, when I try to include it in a module that returns another object, it's resolved to undefined.
For example the code below is able to resolve Globals to the properties it exposes
define(
['marionette', 'templates', 'newapp/globals', 'newapp/views/Loader'],
function(M, T, Globals, mixins){
"use strict";
return M.ItemView.extend(
_.extend({}, mixins, {
template: T.brandPageInfo,
events: {
'click #getProductsForBrands': 'getProductsForBrands',
'click button[id^="goto__"]': 'actionOnGotoButtons'
},
onRender: function() {
this.flatIconsOnHover();
},
getProductsForBrands: function(e) {
e.preventDefault();
var searchQuery = this.model.get('name');
Globals.navigate('search?q=' + searchQuery, {trigger: true});
}
})
)
})
But the code below gives an error: Globals is undefined
define(
[
'newapp/collections/Boards', 'newapp/globals'
],
function(
BoardsCollection, Globals
) {
var boardsList;
return {
ensureBoardList: function() {
var defer = $.Deferred();
if (!boardsList || (boardsList && !boardsList.length)) {
boardsList = new BoardsCollection();
boardsList.fetch({
data: {_: (new Date()).getTime()},
success: function (boardsListCbData) {
boardsList = boardsListCbData;
defer.resolve(boardsList);
}
})
} else {
defer.resolve(boardsList);
}
return defer.done(function (boardsList) {
//make the boardsList usable for direct UI rendering by any view
return Globals.utilities.getFormattedBoardsCollection(boardsList);
});
}
}
})
How do I make Globals accessible in the second example?
Make sure you don't have any circular dependencies e.g.:
globals depends on newapp/controllers/index
newapp/controllers/index depends on the last module you displayed (we'll call it module M)
module M depends on global
Since each module depends on the other, the only thing RequireJS can do is set one of them to undefinedto "break the cycle" and get the other modules to load.
As far as I can tell, this is the most probable source of your problem, not the fact that you're returning another object.
I have some issue with some requireJS setup. I posted a question before but the scope of the latest changed now.
I have some
requirejs.config({
paths: {
'tmpl': 'vendor/upload/tmpl.min'
}
});
require({
paths: {
'videoupload': 'vendor/upload/jquery.ui.videoupload'
}
}, ['js/main_video.js'], function (App) {
App.initial_video_upload();
});
and finally in main_video.js :
define(['tmpl', 'videoupload'], function () {
function initial_video_upload(tmpl, videoupload) {
'use strict';
$('#videoupload').videoupload({
//...some code
});
}
return{
initial_video_upload: initial_video_upload
}
}
);
This code works perfectly if I don't use requireJS (loading classically each file). In fact, when this code is triggered, I keep on having a message Uncaught TypeError: Object [object Object] has no method 'tmpl', this method is defined in tmpl.min.js. And this method is invoked in vendor/upload/jquery.ui.videoupload, as so
$.widget('videoupload', {
//...
_renderVideo: function (video) {
this._templateElement().tmpl({
id: video.id,
name: video.title
}).appendTo(this._listElement()).find(
this.options['delete-selector']
);
return this;
},
//...
How can I manage that ? (I had earlier an error time out message for this method tmpl, but it disappeared now, so I don't think this is it)
In the configuration object, the path is not the full path to the JS file BUT the path to the directory containing the JS file, so you may want to do something like this in the main_video.js file:
requirejs.config({
paths:{
'upload': 'vendor/upload'
}
});
define(['upload/tmpl','upload/jquery_videoupload'],function(tmpl, videoupload) {
function initial_video_upload(tmpl,videoupload){
'use strict';
$('#videoupload').videoupload({
//...some code
});
}
return{
initial_video_upload: initial_video_upload
}
}
);
And in the main app:
requirejs.config({
paths:{
'js': 'path/to/your/js/folder'
}
});
require(['js/main_video'], function(App) {
App.initial_video_upload();
});
There's a problem in the questions code, so this:
define(['tmpl', 'videoupload'], function () {
should become this:
define(['tmpl', 'videoupload'], function (tmpl, videoupload) {
The first one doesn't expose loaded dependencies to local variables of closure function, so that's might be a problem, although it's not very clear if it's the only one, from the provided code.
I would also like to mention, that it's not a good thing to use multiple requre.js configs, if you're intended to use optimizer. The configs will be overwritten by the last one, so it's a good idea actually to have only one config for the whole project.
Like this:
requirejs.config({
paths: {
'tmpl': 'vendor/upload/tmpl.min',
'videoupload': 'vendor/upload/jquery.ui.videoupload'
}
});