This is from knockout.dirtyFlag.js
;(function (ko) {
ko.DirtyFlag = function (objectToTrack, isInitiallyDirty, hashFunction) {
hashFunction = hashFunction || ko.toJSON;
var
_objectToTrack = objectToTrack,
_lastCleanState = ko.observable(hashFunction(_objectToTrack)),
_isInitiallyDirty = ko.observable(isInitiallyDirty),
result = function () {
var self = this;
self.isDirty = ko.computed(function () {
return _isInitiallyDirty() || hashFunction(_objectToTrack) !== _lastCleanState();
});
self.reset = function () {
_lastCleanState(hashFunction(_objectToTrack));
_isInitiallyDirty(false);
};
return self;
};
return result;
};
})(ko);
In my model I have a define setup like this:
define([
"lib/knockout",
"lib/knockout.dirtyFlag"
],
function(ko) {
...
self.dirtyFlag = new ko.DirtyFlag([
}
basically I get an error saying that DirtyFlag is undefined.
What do I need to do?
Well, looks like I got it working, so I'll post my findings:
In my requirejs config I added this:
shim: {
"lib/knockout/knockout.dirtyFlag": {
deps: [
"lib/knockout/knockout"
],
init: function (ko) {
var self = this;
ko.DirtyFlag = self.ko.DirtyFlag;
return ko;
}
}
I'm not very familiar with javascript or requirejs, but init seems to put the dep in "ko" and then I am able to create a DirtyFlag on ko. self.ko.DirtyFlag is the actual knockout.dirtyFlag javascript.
You are requiring lib/knockout and lib/knockout.dirtyFlag. Do you need both ?
If you need both, try:
define([
"lib/knockout",
"lib/knockout.dirtyFlag"
],
function(ko, kodf) {
...
self.dirtyFlag = new kodf.DirtyFlag([
}
You could also try:
define([
"lib/knockout",
"lib/knockout.dirtyFlag"
],
function(k) {
...
self.dirtyFlag = new ko.DirtyFlag([
}
As I think you are defining ko in the require as well as in knockout.dirtyFlag.
I have ended with wrapping kolite classes with define methods. Below example with command, but it will be same for others.
requirejs.config({
paths: {
knockout: 'Scripts/libs/knockout/knockout-2.2.1.debug',
command: 'Scripts/libs/knockout/knockout.command'
},
shim: {
knockout: {
exports: 'ko'
},
command: {
deps: ['knockout'],
exports: 'ko'
}
});
And wrapped command
define(['knockout'], function(ko) {
... // command original code
return ko;
)
in my module
define(['command'], function (ko) {
var doYourStaff = 0;
return doYourStaff;
});
We have added support for RequireJS for all three libs now, you can use the latest version from master.
Related
I'm using RequireJS in my Web Application.
I found little step by step information on how modules should interact in practice.
Mostly theory. Or some too hard examples that I can't understand yet with my current experience in modules.
Directory structure:
| application
| -- app/
| -- customizer.js
| -- sorting.js
| -- config.js
| -- require.js
What is right way to decouple modules and pass parameters
between modules if event fired?
config.js:
requirejs.config({
baseUrl: "...",
paths: {
customizer: 'app/customizer',
sorting: 'app/sorting'
},
config: {
'_#r6': {
view: view,
selector: {
sorting: {
main: ".sort-bar",
items: ".sorting-item"
}
}
}
}
});
require(['module', 'customizer', 'sorting'],
function(module, customizer, sorting) {
// Variables
var config = module.config();
// Modules init data
var init_data = {
// Customizer module settings
customizer: {
config: config
},
// Sorting module settings
sorting: {
config: config
}
};
// Init modules
customizer.init(init_data.customizer);
sorting.init(init_data.sorting);
});
sorting.js:
define(['jQuery', 'customizer'], function($, customizer) {
var config;
var facade = {};
var selector = {};
var callbacks = {
// Events
sortItems: function() {
var selector = callbacks.getSelector();
$(selector.items).find("a").on("click", function(e) {
e.preventDefault();
// some actions with DOM
// then call function from "customizer.js" module
// or change some properties in the module
// How to decouple modules there?
customizer.itemsReload();
});
},
setConfig: function(value) {
config = value;
},
getConfig: function() {
return config;
},
setSelector: function(value) {
selector = value;
},
getSelector: function() {
return selector;
}
};
return {
init: function(atts) {
facade = this;
callbacks.setConfig(atts.config);
callbacks.setSelector(config.selector.sorting);
callbacks.sortItems();
}
}
});
customizer.js:
define(['lodash', 'templates'], function(_, templates) {
var config = {};
var isLoaded;
var callbacks = {
setConfig: function(value) {
config = value;
},
itemsLoad: function() {
// Some code
isLoaded = true;
}
};
return {
init: function(atts) {
facade = this;
// Pre Setup
callbacks.setConfig(atts.config);
items.itemsLoad();
},
itemsReload: function() {
callbacks.itemsLoad();
}
}
});
You can use some kind of EventBus. There are plenty of them available as modules.
Flow is quiet simple, customizer listens for an event which is triggered by sorting.
Probably this can be achieved with jQuery but I am not a jQuery expert :)
Here i'm trying to extend Amasty js widget in my module using mixin.
I have created requirejs-config.js file like below
var config = {
config: {
mixins: {
'amShopbyAjax': {
'vendor_CustomCatalog/js/amasty/amShopbyAjax-override': true
}
}
}
};
I have created js file like below
define([
"jquery",
"jquery-ui-modules/widget"
], function ($) {
'use strict';
var amShopbyWidgetMixin = {
selectors: {
category_products_wrapper: '#amasty-shopby-category-product-list',
},
reloadHtml: function (data) {
console.log("Sdfsdfsdf");
return this._super();
},
callAjax: function (clearUrl, data, pushState, cacheKey, isSorting) {
console.log("sdnjkasndnsadj");
return this._super();
}
};
return function (targetWidget) {
$.widget('custom.amShopbyAjax', targetWidget, amShopbyWidgetMixin);
return $.custom.amShopbyAjax;
};
});
After that I ran sudo bin/magento setup:static-content:deploy -f and clear cache then I am getting "Uncaught TypeError: base is not a constructor" error
Think that you should change custom.amShopbyAjax to mage.amShopbyAjax
return function (targetWidget) {
$.widget('mage.amShopbyAjax', targetWidget, amShopbyWidgetMixin);
return $.mage.amShopbyAjax;
};
The widget alias should be like for the target widget and the widget by parent alias should be returned
i have the following scenario:
i have a global namespace called fort which has a few common functions that i need and it looks like this :
fort.js
define("fort", ["fortHistory"], function (FortHistory) {
function Fort(){}
Fort.prototype.history = FortHistory;
return Fort;
});
fortHistory is a small module i created defined as so:
fortHistory.js
"use strict";
define("fortHistory", function () {
function FortHistory() {
}
FortHistory.prototype.doSomething = function(){...}
return FortHistory;
});
i then do this in my config.js
require.config( {
enforceDefine: true,
paths: {
'fort': 'develop/js/fort',
'fortHistory' : 'develop/js/webapp/fortHistory'
},
shim: {
fort:{
exports: 'fort'
}
}
} );
define( function() {} );
finally in main.js i have:
define('fort', [], function(fort){
window.fort = fort;
});
the hope was that i could then make a call such as :
fort.fortHistory.doSomething();
instead fort is undefined so i am assuming i have misinterpreted how requirejs works
You've named it history, not fortHistory:
Fort.prototype.history = FortHistory;
Try calling it via fort.history.doSomething();.
I'm trying out requireJS in order to improve the loading of Javascript on an ASP.NET MVC app, using Knockout.
I have some files defining custom ko bindings like that:
(function (ko, bindings) {
bindings.stopBinding = {
init: function () {
return { controlsDescendantBindings: false };
}
};
bindings.anotherBinding = { ... };
})(ko, ko.bindingHandlers);
If I try to load it as a requireJS module this way:
define(['jquery', 'knockout', 'custom/knockout.bindings'], function ($, ko){
ko.applyBindings(...);
});
I get a ko is not defined error.
I know that I could enclose this file in a require callback for instance in order ot make it work:
require(['knockout'], function (ko) {
(function (ko, bindings) {
bindings.stopBinding = {
init: function () {
return { controlsDescendantBindings: false };
}
};
bindings.anotherBinding = { ... };
})(ko, ko.bindingHandlers);
});
Is there another way to allow this file to work without having to update each and every legacy JS file in the application ? I thought of using shim, but I didn't get anywhere, but I'm quite a noob with requireJS, so maybe I'm missing something obvious.
Thanks to this answer, I managed to inject Knockout back in the global namespace, making it available to legacy Javascript files that needed it.
First, create a module that injects ko in the global namespace:
define('knockout.inject', ['knockout'], function (k) {
window.ko = k;
return k;
});
Then, map the module to knockout to execute it for every knockout dependency.
var require = {
baseUrl: "/Scripts",
paths: {
//...
"knockout": "knockout-3.3.0.debug",
"knockoutbindings": "knockout.bindings",
},
shim: {
"knockoutbindings": {
deps: ["knockout"]
}
},
map: {
// inject ko back in the global namespace
'*': {
'knockout': 'knockout.inject'
},
// prevent cycles
'knockout.inject': { 'knockout': 'knockout' }
}
};
Am building a single page site with backbone.js. Am using require.js to make the code modular,
but am having problems initializing the backbone router for urls.
I load the main js file using require.js, heres what it looks like
enter code here
//App Namespace
var Chrono = Chrono || {};
//App Config Namespace
Chrono.Config = Chrono.Config || {};
//App Views Namespace
Chrono.Views = Chrono.Views || {};
//Config
Chrono.Config = {
url:"http://localhost/chronotech/",
site_url:"http://localhost/chronotech/index.php/",
data_source:"http://localhost/chronotech/assets/datasource/"
};
require.config({
paths : {
'backbone': 'libs/backbone',
'jquery':'libs/jquery.min',
'underscore':'libs/underscore',
'text':'libs/require/text'
},
baseUrl : 'assets/js'
});
require(
['require', 'underscore', 'backbone', 'jquery'],
function(require,_, Backbone, $) {
require(['app'],
function(require) {
} );
} );
And the app.js looks like this
define(['backbone','routers/workspace'],
function( Backbone,Workspace) {
$(function () {
var space = new Workspace();
} );
} );
And router file looks like this
define(['jquery','backbone'],
function($, Backbone) {
var Workspace = Backbone.Router.extend( {
routes: {
"about":"aboutPage",
"team":"teamPage",
"contact":"contactPage",
"work":"portfolioPage",
"products":"productPage"
},
aboutPage : function() {
alert("about");
},
teamPage : function() {
alert("team");
},
contactPage: function() {
alert("contact");
},
portfolioPage : function() {
alert("work");
},
productPage : function() {
}
} );
return Workspace;
} );
When i load the page, i get the following errors:
"Uncaught ReferenceError: $ is not defined",
"Uncaught TypeError: Cannot read property 'Router' of null".
What am i doing wrong?
define(['backbone','routers/workspace'],
function( Backbone,Workspace) {
$(function () {
var space = new Workspace();
} );
} );
Is it a separate file? Maybe you need to load jQuery in order to use $?