requirejs - shim configuration - jquery-ui

I am using Almond and the r.js optimizer to combine all my scripts in a single file for a Backbone.js-based Single Page Application.
My build file:
({
name: '../bower_components/almond/almond',
include: ['main'],
insertRequire: ['main'],
baseUrl: 'src',
optimize: 'uglify2',
mainConfigFile: 'src/main.js',
out: 'javascripts/scripts.js',
preserveLicenseComments: false,
paths: {
jquery: '../bower_components/jquery/dist/jquery',
underscore: '../bower_components/underscore/underscore',
backbone: '../bower_components/backbone/backbone',
kineticjs: '../bower_components/kineticjs/kineticjs',
'jquery-ui': '../bower_components/jquery-ui/ui',
'jquery.layout': '../bower_components/jquery.layout/dist/jquery.layout-latest'
},
shim: {
'jquery.layout': {
deps: [
'jquery-ui/core',
'jquery-ui/draggable',
'jquery-ui/effect',
'jquery-ui/effect-slide'
],
exports: 'jQuery.fn.layout'
}
}
})
In my Backbone view I initialize the jquery-layout plugin:
define(['backbone', 'underscore', 'jquery.layout'], function(Backbone, _) {
'use strict'
return Backbone.View.extend({
el: $('#application'),
initialize: function() {
this.$el.layout({
west: {
size: '50%',
closable: false,
slidable: false,
resizable: true
}
});
}
});
});
The panes show up correctly, however I cannot resize any of them. I found that $.fn.draggable (JQuery UI Draggable widget) is not being initialized at the time when the jquery-layout plugin is declared.
This indicates that probably the widget is not being loaded. So I checked the combined source file and noticed that the JQuery UI Draggable widget code appears before the jquery-layout plugin code, which means the dependencies are inserted in the correct order. Printing $.fn.draggable in the Firebug console also shows that the widget is available, at least after the document is ready.
jQuery, underscore, backbone, jQuery UI are all AMD modules. jquery-layout has no AMD compatibility, hence the shim config. It depends on JQuery UI's ui.core and ui.draggable per their docs.
For all of this to not sound too abstract, here is a demo of the jquery-layout plugin.
I have "wasted" over 8 hours trying to figure this out in vain, any help on how to fix this would save my day. Most probably this would involve only some fix of my shim config in the build file.

I solved the problem by making the non AMD-aware jquery-layout plugin AMD-compatible. I used the onBuildWrite hook of the r.js optimizer in the build file. This way the jQuery UI dependency ui.draggable is initialized before the code of the non AMD-aware plugin loads:
({
name: '../bower_components/almond/almond',
include: ['main'],
insertRequire: ['main'],
baseUrl: 'src',
optimize: 'uglify2',
mainConfigFile: 'src/main.js',
out: 'javascripts/scripts.js',
preserveLicenseComments: false,
paths: {
jquery: '../bower_components/jquery/dist/jquery',
underscore: '../bower_components/underscore/underscore',
backbone: '../bower_components/backbone/backbone',
kineticjs: '../bower_components/kineticjs/kineticjs',
'jquery-ui': '../bower_components/jquery-ui/ui',
'jquery.layout': '../bower_components/jquery.layout/dist/jquery.layout-latest'
},
shim: {
'jquery.layout': {
deps: ['jquery', 'jquery-ui/draggable', 'jquery-ui/effect', 'jquery-ui/effect-slide'],
exports: 'jQuery.fn.layout'
}
},
onBuildWrite: function(moduleName, path, contents) {
if (moduleName == 'jquery.layout') {
contents = "define('jquery.layout', ['jquery', 'jquery-ui/draggable', 'jquery-ui/effect', 'jquery-ui/effect-slide'], function(jQuery) {" + contents + "});";
}
return contents;
}
})

Following the answer from #Genti and using latest jquery-ui, following shim worked for me.
shim: {
'jquery.layout': {
deps: ['jquery', 'jquery-ui/core', 'jquery-ui/widgets/draggable', 'jquery-ui/effect', 'jquery-ui/effects/effect-slide', 'jquery-ui/effects/effect-drop', 'jquery-ui/effects/effect-scale'],
exports: 'jQuery.fn.layout'
}
}

Related

(OpenLayers) ReferenceError: ol is not defined

I'm working on Angular-CLI based project.
I need to include OpenLayers3 into my project using systemjs.
When I setup systemjs on my project for including Openlayers javascript file I had error ReferenceError: ol is not defined.
This is my system-config.ts file
const map: any = {
'ol': 'vendor/openlayers/dist/ol.js'
};
/** User packages configuration. */
const packages: any = {
'tether': {
defaultExtension: 'js',
},
'vendor/ng2-slimscroll': {
defaultExtension: 'js',
},
'ol': {
defaultExtension: 'js'
}
};
This error happens, but I still find that ol.js file has been called in my browser network debugger.
Also, this error gone when I define ol.js using regular <script> tag in head of my index page.

How can I use the Vue.js code from a webpack bundle in a Razor page?

Here is my Razor page code:
#using System.Web.Optimization;
#{ BundleTable.Bundles.Add(
new ScriptBundle("~/Scripts/Vuejs")
.Include("~/Static/Scripts/Vuejs/vue.min.js")); }
#section Scripts {
#Scripts.Render("~/Static/vue/assets/bundle.js")
#Scripts.Render("~/Scripts/Vuejs")
}
<div id="app_container">
{{text}}
</div>
and here is the entry of the webpack javascript:
import Vue from 'vue';
const v = new Vue({
el: '#app_container',
data: { text: 'abcdefg' }
});
Webpack config:
export default {
entry: [
'babel-polyfill',
'./src/index.js'
],
output: {
filename: 'bundle.js',
path: 'C:/WebSandbox/Static/vue/assets',
publicPath: '/vue/assets/'
},
devtool: 'source-map',
module: {
loaders: [
{ test: /\.vue$/, loader: 'vue' },
{ test: /\.js/, loader: 'babel', exclude: /node_modules/ },
{ test: /\.json$/, loader: 'json' },
{ test: /\.txt/, loader: 'raw' }
]
},
plugins: [
new webpack.optimize.DedupePlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
APP_ENV: JSON.stringify('browser')
}
})
]
};
All the javascript files are in place and when open the page I can see the mapped code from Developer Tools of Chrome. And if I make a break point in the javascript code, it will be hit.
But the text displayed is "{{text}}", not "abcdefg".
If I added following code after the div:
<script>
const v = new Vue({ el: "#app_container", data: { text: "abcdefg" } });
</script>
or add following code and remove the javascript file from #section Scripts part
<script src='~/Static/vue/assets/bundle.js'></script>
It works.
So how can I make my webpack bundle work with the #Scripts.Render in Razor page?
OK, now I found why the bundle not working:
Because the #RenderSection("Scripts", false) was written in the header of _Layout.cshtml. So the bundle JavaScript file will be referenced in the header. But when I switch to the raw reference (script tag), it will be after my div tag where it should be.
When I change the bundle part to:
#section ScriptBlock {
#Scripts.Render("~/Static/vue/assets/bundle.js")
}
It works.
The #RenderSection("ScriptBlock", false) was written in the bottom of the _Layout.cshtml right after the closing tag of body.
I use vuejs with asp.net with browserify rather than webpack.
And the packing should be an independent build step.
I setup a gulp task to take my vue code and bundle it up and place it in the scripts folder of asp.net.
I think you need to do something similar here.

Why does using requirejs 2 stop my backbone / jQuery mobile app working?

I have a very simple proof of concept app built with jQuery Mobile, Backbone.js, and require.js.
I am using Backbone's router, and I have jQuery Mobile's routing disabled. It works perfectly.
I am using require.js 1.04. However: when I use requirejs 2.1.14, then I can't seem to disable jQuery Mobile's routing, and hence Backbone's routing stops working. Can't figure it out.
The following code works if I remove jQuery mobile, but stops working if I put jQuery mobile back in. Similarly, it will work with Require.js 1.0.4, but not with require.js 2.1.14:
index.html:
<html>
<body>
Click Here
<script data-main="main" src="require.js"></script>
</body>
</html>
main.js
require.config({
paths : {
backbone : 'libraries/backbone/backbone',
underscore : 'libraries/underscore/underscore',
jquery : 'libraries/jquery/jquery-1.7.1',
jqm : 'libraries/jquery.mobile/jquery.mobile',
router: 'router'
},
shim: {
jqm: {
exports: 'jqm',
deps: ['jquery']
},
underscore: {
exports: 'underscore'
},
backbone: {
exports: 'backbone',
deps: ['jquery', 'underscore']
}
}
});
require(
['jquery', 'jqm', 'underscore', 'backbone', 'router'],
function ($, $$, underscore, Backbone, router) {
$.mobile.ajaxEnabled = false;
$.mobile.linkBindingEnabled = false;
$.mobile.hashListeningEnabled = false;
$.mobile.pushStateEnabled = false;
$.mobile.changePage.defaults.changeHash = false;
router.init();
});
router.js
define(['jquery', 'jqm', 'underscore', 'backbone'],
function($, $$, _, Backbone) {
var init = function () {
$.mobile.ajaxEnabled = false;
$.mobile.linkBindingEnabled = false;
$.mobile.hashListeningEnabled = false;
$.mobile.pushStateEnabled = false;
$.mobile.changePage.defaults.changeHash = false;
var AppRouter = Backbone.Router.extend({
routes: {
"posts/:id" : "getSomePost",
"*action": "defaultRoute"
},
getSomePost: function(id) {
alert( "Get post number " + id );
},
defaultRoute: function( actions ){
console.log('Action: ' + actions );
}
});
// Instantiate the backbone router
var app_router = new AppRouter();
// Start Backbone history
Backbone.history.start();
};
return { init : init };
});
This problem is seriously baking my noodle!!
When I load up the app, I see a link saying "Click here". When the app uses requirejs-1.0.4 (or without jquery mobile) it works, I get an alert saying "get post number 1", and the URL looks like:
http://myapp.dev/src/#posts/1
but when using requirejs-2.1.14 and jQuery Mobile, I the URL quickly changes to this:
http://myapp.dev/src/posts/1
and nothing happens.
Help!
I finally found the answer to this problem. The issue is the timing of jQuery Mobile configuration. According to the jQuery Mobile docs:
Because the mobileinit event is triggered immediately, you'll need to
bind your event handler before jQuery Mobile is loaded
So I rewrote main.js like so:
require.config({
paths : {
backbone : 'libraries/backbone/backbone',
underscore : 'libraries/underscore/underscore',
jquery : 'libraries/jquery/jquery-1.7.1',
jqmconfig : 'jquerymobile.config',
jqm : 'libraries/jquery.mobile/jquery.mobile',
router: 'router'
},
shim: {
jqm: {
exports: 'jqm',
deps: ['jquery', 'jqmconfig']
},
underscore: {
exports: 'underscore'
},
backbone: {
exports: 'backbone',
deps: ['jquery', 'jqm', 'underscore']
}
}
});
require(
['jquery', 'backbone', 'jqmconfig', 'jqm', 'router'],
function ($, Backbone, jqmconfig, $$, router) {
router.init();
});
And added a new file called jquerymobile.config.js:
define(['jquery'], function ($) {
$(document).on('mobileinit', function () {
// Prevents all anchor click handling
$.mobile.linkBindingEnabled = false
// Disabling this will prevent jQuery Mobile from handling hash changes
$.mobile.hashListeningEnabled = false
$.mobile.ajaxEnabled = false;
$.mobile.pushStateEnabled = false;
});
});
This code fires after jQuery has loaded, but BEFORE jQuery Mobile has loaded, which is the key!
For reference, this is the blog post that helped me figure it out:
http://www.justinmccandless.com/blog/Yeoman%2C+Requirejs%2C+jQuery+Mobile%2C+Backbone%2C+and+a+Lot+of+Config+Problems

Angular UI slider with Require JS fires before jQuery UI

I am building an AngularJS application using RequireJs, AngularUI and jQuery UI.
I occasionally get the following error when using the slider:
TypeError: Object [object Object] has no method 'slider'
at init (http://example.com/Assets/js/lib/angular-ui/slider.js?v=635137928871837150:18:29)
at ngModel.$render (http://example.com/Assets/js/lib/angular-ui/slider.js?v=635137928871837150:55:25)
at Object. (http://example.com/Assets/js/lib/angular-1.0.7/angular.min.js?v=635137928871837150:140:131)
at Object.e.$digest (http://example.com/Assets/js/lib/angular-1.0.7/angular.min.js?v=635137928871837150:86:286)
at Object.e.$apply (http://example.com/Assets/js/lib/angular-1.0.7/angular.min.js?v=635137928871837150:88:506)
at e (http://example.com/Assets/js/lib/angular-1.0.7/angular.min.js?v=635137928871837150:95:38)
at p (http://example.com/Assets/js/lib/angular-1.0.7/angular.min.js?v=635137928871837150:98:123)
at XMLHttpRequest.t.onreadystatechange (http://example.com/Assets/js/lib/angular-1.0.7/angular.min.js?v=635137928871837150:99:259)
angular.min.js?v=635137928871837150:62
(anonymous function) angular.min.js?v=635137928871837150:62
(anonymous function) angular.min.js?v=635137928871837150:52
e.$digest angular.min.js?v=635137928871837150:87
e.$apply angular.min.js?v=635137928871837150:88
e angular.min.js?v=635137928871837150:95
p angular.min.js?v=635137928871837150:98
t.onreadystatechange angular.min.js?v=635137928871837150:99
If I refresh the page the error goes away and it only happens occasionally anyway.
I am using:
Require version 2.1.8.js
Current version of Angular Ui Slider (https://github.com/angular-ui/ui-slider/blob/master/src/slider.js)
The relevant parts of my Require Config are:
require.config({
shim: {
jqueryui: {
deps: ['jquery']
},
'angular': { 'exports': 'angular' },
angularResource: { deps: ['angular'] },
angularMocks: { deps: ['angular'] },
angularSortable: { deps: ['angular', 'jquery', 'jqueryui'] },
angularSlider: { deps: ['angular', 'jquery', 'jqueryui'] }
},
paths: {
angular: '/Assets/js/lib/angular-1.0.7/angular.min',
angularResource: '/Assets/js/lib/angular-1.0.7/angular-resource.min',
angularMocks: '/Assets/js/lib/angular-1.0.7/angular-mocks',
angularSortable: '/Assets/js/lib/angular-ui/sortable',
angularSlider: '/Assets/js/lib/angular-ui/slider',
jquery: '/Assets/js/lib/jquery-1.9.1.min',
jqueryui: '/Assets/js/lib/jquery-ui-1.10.0'
}
});
I am bootstrapping my application like so:
require(['require', 'jquery', 'jqueryui', 'angular', 'angularResource', 'angularSortable', 'angularSlider'],
function (require, $, jqueryui, angular) {
'use strict';
var contentApp = angular.module('testApp', ['ngResource', 'ui.sortable', 'ui.slider']);
require(['TestController'],
function () {
$(document).ready(function () {
var $angularRootElement = $('#wrapper');
angular.bootstrap($angularRootElement, [contentApp['name']]);
$angularRootElement.addClass('ng-app');
});
});
}
);
I presume the problem is that occasionally jQuery UI hasn't loaded before the Angular UI slider code runs. Although, I can see in the network tab in Chrome that jQuery UI was downloaded before the slider.
Can anyone give me some ideas on how to debug this?
Thanks

Datepicker jqueryui not works with require.js and backbone.js

Jquery ui datepicker not works on click on input.
main.js
require.config({
baseUrl: "js",
paths: {
html5shiv: "libs/html5shiv",
jquery: "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min",
jqueryui: "http://code.jquery.com/ui/1.10.3/jquery-ui",
tablesorter: "libs/jquery.tablesorter.min",
script: "script",
underscore: "libs/underscore.min",
backbone: "libs/backbone.min",
utils: "utils",
collectorModel: "models/collectorModel",
collectorCollection: "collections/collectorCollection",
tollectorRouter: "routers/tollectorRouter",
edit: "views/collector/tollector_edit",
index: "views/collector/collector_index",
neww: "views/collector/collector_new",
row: "views/collector/collector_row",
show: "views/collector/collector_show",
'templates': 'templates'
},
shim: {
jqueryui: {
deps: ["jquery"],
exports: "Jqueryui"
},
tablesorter: {
deps: ["jquery"],
exports: "TableSorter"
},
script: {
deps: ["jquery", "jqueryui", "tablesorter"],
exports: "Script"
},
jqueryui: {
deps: ["jquery"]
},
underscore: {
exports: "_"
},
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
}
}
});
require(["backbone", "underscore", "collectorCollection", "collectorRouter", "script"],
function (Backbone, _, CollectorCollection, CollectorRouter) {
var collectors = new CollectorCollection();
var router = new CollectorRouter({collectors: collectors});
Backbone.history.start();
});
Template: collector_edit.html
input type="text" class="inputs dateInput" name="endDate" placeholder="End date" value="<%= endDate %>
scripts.js
$(document).ready(function () {
$(".dateInput").datepicker({dateFormat: "dd/mm/yy"});
});
it worked before using backbone and RequireJS
When using requireJS your dependencies do not exist in the global scope anymore but only inside modulde that requires them. Try changing your script JS to:
define(['jqueryui'], function( jqueryui ) {
$(document).ready(function () {
$(".dateInput").datepicker({dateFormat: "dd/mm/yy"});
});
})

Resources