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' }
}
};
Related
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 am trying to understand how require js works by building knockout components.I have built 2 separate knockout components for testing. My directory structure is as follows:
- App
|_ Components
|_ Like-Widget
|_like-widget.js
|_like-widget.html
|_ sign-in
|_sign-in.js
|_sing-in.html
|_ startup.js
- Scripts
|_ knockout.js
|_ knockout-es5.js
|_ app.js
I have configured require.js as follows in app.js file
require.config({
paths: {
ko: "/Scripts/knockout-3.4.0",
kox: "/Scripts/knockout-es5",
jquery: "/Scripts/jquery-1.10.2.min",
text: "/Scripts/text"
},
shim: {
"kox": {
deps:["ko"]
}
},
baseUrl: "/App/Components"
});
require(["/App/Components/startup.js"]);
Here is my startup.js file
define(['ko'], function (ko) {
ko.components.register('like-widget', { require: 'like-widget/like-widget' });
ko.components.register('sign-in', { require: 'sign-in/sign-in' });
ko.applyBindings();
});
my like-widget.js and sign-in.js files are almost identical for testing purpose
define(["kox", "text!like-widget/like-widget.html"], function (ko, template) {
function myViewModel(params) {
var self = this;
self.personName = 'Bob';
self.personAge = 23;
ko.track(this);
};
return {
viewModel: myViewModel,
template: template
};
});
define(["kox", "text!sign-in/sign-in.html"], function (ko, template) {
function signInViewModel(params) {
var self = this;
self.userName = 'User 1';
ko.track(this);
};
return {
viewModel: signInViewModel,
template: template
};
});
this is how I am referring to require.js in my html page
<script type='text/javascript' data-main="/Scripts/app.js" src="~/Scripts/require.js"></script>
The problem is that my like-widget component is working fine but as soon as I try to use my sign-in component, I am getting an error
GET http://localhost:65182/App/Components/knockout.js
Uncaught Error: Script error for "knockout", needed by: kox
http://requirejs.org/docs/errors.html#scripterror
From the error it seems that requirejs is trying to load knockout from incorrect location, my knockout.js is not in components directory but in scripts directory. What I can't understand is how it is correctly loading the like-widget component?
I am new to requirejs so I am assuming I am making some naive mistake, can you please point it out?
If you look at the source code for knockout-es5 plugin you will see that it requires the knockout path to be set to 'knockout', not 'ko'.
} else if (typeof define === 'function' && define.amd) {
define(['knockout'], function(koModule) {
ko = koModule;
attachToKo(koModule);
weakMapFactory = function() { return new global.WeakMap(); };
return koModule;
});
}
If you change your require config path for knockout
require.config({
paths: {
knockout: "/Scripts/knockout-3.4.0",
// instead of ko: "/Scripts/knockout-3.4.0"
}
it should work. You can also remove the shim for knockout-es5 (kox in your example) since it shouldn't be needed.
Instead of having one giant js file that has a whole bunch of "defines", how do I call my various "define" functions from other files?
I've been copying these examples, but still cannot get it to work:
example-multipage
example-multipage-shim
example-jquery-shim
Here is what I have so far:
main.js
require.config({
baseUrl: '',
paths: {
jquery: '../libraries/jquery-1.10.2.min',
simControlView: '../javascripts/simControlView'
}
});
require(['jquery','loadPage'], function( $,loadPage)
{
loadPage();
});
define('loadPage', ['jquery'], function($)
{
var simControlView = require(['./simControlView']);
return function()
{
simControlView.showSimControlView(); //having problem here
};
});
simControlView.js
define(['jquery'], function ($) {
return {
showSimControlView: function () {
console.log("Hi!!");
}
}
});
Here is the error that I'm getting:
Uncaught TypeError: Object function d(e,c,h){var
g,k;f.enableBuildCallback&&(c&&H(c))&&(c.__requireJsBuild=!0);if("string"===typeof
e){if(H(c))return v(A("requireargs", "Invalid require
call"),h);if(a&&s(N,e))return Ne;if(j.get)return
j.get(i,e,a,d);g=n(e,a,!1,!0);g=g.id;return!s(r,g)?v(A("notloaded",'Module
name "'+g+'" has not been loaded yet for context: '+b+(a?"":". Use
require([])"))):r[g]}K();i.nextTick(function(){K();k=q(n(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});C()});return
d} has no method 'showSimControlView'
See anything I'm doing wrong? Any help is appreciated!
Try moving all the dependencies to the dependency list you pass to define().
Also, the ordering may be important. I.e. the define() of a module may need to come before the require() that requires it (talking about the 'loadPage' module).
Also, if your paths config calls a module 'simControlView', then it needs to be referred to as 'simControlView', and not as './simControlView'.
E.g.:
define('loadPage', ['jquery', 'simControlView'], function($, simControlView) {
return function() {
simControlView.showSimControlView();
};
});
require(['jquery', 'loadPage'], function($, loadPage) {
loadPage();
});
I am experiencing some strange issue. I have this
require({
paths: {
'template': 'tmpl.min',
'videoupload.widget': 'jquery.ui.videoupload'
}
}, ['js/main_video.js'], function(App) {
App.initial_video_upload();
});
and this
define(['template','videoupload.widget'],function() {
function initial_video_upload(){
'use strict';
$('#videoupload').videoupload({
//...some code
});
}
return{
initial_video_upload: initial_video_upload
}
}
);
in the file jquery.ui.videoupload.js, I have some call to a tmpl method which is defined in tmpl.min.js, but I get the message
Uncaught TypeError: Object [object Object] has no method 'tmpl'
There are two issues here:
Your first snippet is passing configuration options to a require function. require, is a way to load dependencies and execute some code using them. If you want to pass configuration options to require.js, requirejs.config is what you want:
// configurations to be used in your module definitions
requirejs.config({
paths: {
'template': 'tmpl.min',
'videoupload.widget': 'jquery.ui.videoupload'
}
});
// load your main module and kick things off
require(['js/main_video.js'], function(App) {
App.initial_video_upload();
});)
Your second snippet is declaring dependencies, but not passing them into the callback:
define(['template','videoupload.widget'],
// these are now accessible within the function's scope:
function(template, videoupload.widget) {
function initial_video_upload(){
'use strict';
$('#videoupload').videoupload({
//...some code
});
}
return{
initial_video_upload: initial_video_upload
}
}
);
Additionally, I'm assuming jQuery is a dependency of your videoupload.widget. How are you loading that? You may need to add an additional "shim" configuration to your requirejs.config:
requirejs.config({
paths: {
'template': 'tmpl.min',
'videoupload.widget': 'jquery.ui.videoupload'
},
shim: {
"videoupload.widdget": ["jquery"]
}
});