Angular2 and Turbolinks - javascript

Here is the situation: I'm using async. script loading with systemJS (by scripts, I mean jQuery, Angular2, ...). Now I would like to implement Turbolinks into this. Everything works just fine, but my angular component is rendered only the first time. If I use Turbolinks to see next page, my component is not rendering. No errors in object inspector and in source code is only this:
<search-app></search-app>
I've tired test in object inspector but after second page lead this is only HTML tag.
Here are my loading scripts in SystemJS in Head tag on my page:
System.config({
meta: {
'/bundles/frontall': { format: 'global' },
'/bundles/raphael': { format: 'global' },
'/bundles/zopim': { format: 'global' },
'/bundles/angular2': { format: 'global' }
},
packages: {
'angular': {
format: 'register',
defaultExtension: 'js'
},
'angular2': {
format: 'global',
defaultExtension: 'js'
},
'rxjs': {
format: 'global',
defaultExtension: 'js'
}
},
paths: {
'angular2/*': 'scripts/angular2/*',
'rxjs/*': 'scripts/rxjs/*'
}
});
System.import('/bundles/frontall').then(function () {
Promise.all([
System.import('/bundles/zopim'),
System.import('/bundles/raphael'),
System.import('bundles/angular2'),
#RenderSection("asyncScripts", required: false)
]).then(function () {
System.import('angular/searchApp');
});
In the frontAll bundle is file site.js, where I re-initing all components:
function componentInit() {
//init material design
$.material.init();
//init texarea autosize
autosize($('textarea'));
//init parallax
$('.parallax-window').parallax();
//init smooth scroll
//SmoothScroll();
//init css3 animate it
$.animateIt();
$.doTimeout();
$.animateItInit();
$.srSmoothscroll({
step: 80,
speed: 90,
ease: 'linear',
target: $('body'),
container: $(window)
});
}
$(function () {
componentInit();
});
$(document).on('page:load', function () {
componentInit();
});
Angular 2 version is beta 7. Does anybody know where is the problem? Thanks a lot!

I need to add this to my angular2 app and it works:
jQuery(function () {
bootstrap(searchApp, [ElementRef, TournamentSearchService]);
});
jQuery(document).on('page:load', function () {
bootstrap(searchApp, [ElementRef, TournamentSearchService]);
});

Related

systemjs auto load plugins after jquery

I am trying to get a handle on systemjs, and understand how to load dependencies: ie load these scripts before this script loads, however I am stuck on doing the reverse...
I have a set of default jQuery plugins that I always want loaded after jQuery is loaded. Is there a way to set this up in the systemjs config so that I always have my plugins loaded when jQuery is loaded? These would need to be loaded after jQuery loads and not before.
Current systemjs config file
System.config({
//defaultJSExtensions: true,
//Create new header in WebExchange to load this beast..
baseUrl: WE_CONTEXT + '/assets',
map: {
css: 'css.js',
//Map JQuery
'jquery': 'https://code.jquery.com/jquery-1.11.0.min.js',
//Begin DataTables
'dataTables': 'https://cdn.datatables.net/1.10.10/js/jquery.dataTables.min.js',
'dataTablesCss': 'https://cdn.datatables.net/1.10.10/css/jquery.dataTables.min.css',
'dataTablesButtonPlugin': 'https://cdn.datatables.net/buttons/1.5.1/js/dataTables.buttons.min.js',
'dataTablesButtonBootstrapPlugin': 'https://cdn.datatables.net/buttons/1.5.1/js/buttons.bootstrap.min.js',
'dataTablesColSearchPlugin': 'plugins/datatables/datatables.colsearch.plugin.js',
'dataTablesResponsivePlugin': 'plugins/datatables/dataTables.responsive.js',
'dataTablesResponsiveCss': 'https://cdn.datatables.net/responsive/2.0.0/css/responsive.dataTables.min.css',
'dataTablesButtonCss': 'https://cdn.datatables.net/buttons/1.5.1/css/buttons.bootstrap.min.css'
//End
},
meta: {
'*.css': {loader: 'css'},
'jQuery' : {
'deps' : []
},
'dataTables': {
//Dependecies to load before module i.e DataTables
'deps': ['dataTablesCss', 'jquery', 'dataTablesColSearchPlugin', 'dataTablesResponsivePlugin', 'dataTablesResponsiveCss']
},
'dataTablesButtonPlugin': {
'deps': ['dataTablesButtonBootstrapPlugin', 'dataTablesButtonCss']
}
},
bundles: {
'jquery': ['dataTables']
//'datatablesCss' : ['dataTables']
}
});
You could try a construct with setTimout, like this:
function waitJQuery () {
if(!window.jQuery) {
setTimeout(() => waitJQuery , 200);
} else {
execute();
}
}
function execute () {
// your code here
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
You check if JQuery is there, if not you execute the waitJQuery again.

SystemJS import fails silently on bundled Angular2 app

I am having trouble with SystemJS.
I have a typical Angular2 application written in Typescript.
I am trying to bundle all my application .js into a single file to optimize load time.
The bundle is created by gulp using systemjs-builder like this :
gulpfile.js
paths.compiledTs = "./wwwroot/app";
gulp.task('bundle:app', function (done) {
var builder = new Builder("/", './systemjs.config.js');
var builderConfig = {
normalize: true,
minify: true,
mangle: true,
runtime: false
};
builder.bundle(paths.compiledTs + '/main.js', paths.compiledTs + '/middleware-app.js', builderConfig)
.then(function () {
done();
})
.catch(function (err) {
console.log(err);
done();
});
});
The bundle is loaded though script tag. It works correcly as a call to System.defined in the browser console shows my modules :
System.defined
System.defined(picture)
Here is my systemjs.config.js. If I understand things correctly, an import to "app" should resolve to wwwroot/app/main.ts, then to the bundle file through the "bundles" parameter.
systemjs.config.js
/**
* System configuration
*/
(function (global) {
// map tells the System loader where to look for things
var map = {
'app': 'wwwroot/app',
'#angular': 'wwwroot/lib/#angular'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main:'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'lodash': { defaultExtension: 'js' },
'moment': { defaultExtension: 'js' },
'pikaday': { defaultExtension: 'js' },
'ng2-translate': { defaultExtension: 'js' },
};
var ngPackageNames = [
'common',
'compiler',
'core',
'forms',
'http',
'platform-browser',
'platform-browser-dynamic',
'router'
];
// Individual files (~300 requests):
function packNgIndex(pkgName) {
packages['#angular/' + pkgName] = { main: 'index.js', defaultExtension: 'js' };
}
// Bundled (~40 requests):
function packNgUmd(pkgName) {
packages['#angular/' + pkgName] = { main: 'bundles/' + pkgName + '.umd.min.js', defaultExtension: 'js' };
}
// Most environments should use UMD; some (Karma) need the individual index files
var setNgPackageConfig = System.packageWithIndex ? packNgIndex : packNgUmd;
// Add package entries for angular packages
ngPackageNames.forEach(setNgPackageConfig);
var config = {
defaultJSExtensions: true,
baseURL: global.baseUrl,
paths: {
"lodash": "wwwroot/lib/lodash.min.js",
"moment": "wwwroot/lib/moment.min.js",
"pikaday": "wwwroot/lib/pikaday.js"
},
map: map,
packages: packages,
meta: {
pikaday: {
deps: ['moment']
},
'angular2/*': {
build: false
},
'rxjs/*': {
build: false
},
'ng2-translate/*': {
build: false
}
},
bundles: {
"wwwroot/lib/bundles/rxjs.min.js": [
"rxjs/*",
"rxjs/operator/*",
"rxjs/observable/*",
"rxjs/add/operator/*",
"rxjs/add/observable/*",
"rxjs/util/*"
],
"wwwroot/lib/bundles/ng2-translate.min.js": [
"ng2-translate/*"
],
"wwwroot/app/middleware-app.js": [
"app/*",
"app/common/busy-indicator/*",
"app/common/config/*",
"app/common/date-picker/*",
"app/common/dialog/*",
"app/common/guards/*",
"app/common/interface/*",
"app/common/login/*",
"app/common/models/*",
"app/common/pagination/*",
"app/common/services/*",
"app/common/storage/*",
"app/i18n/*",
"app/layout/*",
"app/pages/authentication/*",
"app/pages/logs/*",
"app/pages/monitoring/*",
"app/pages/not-found/*",
"app/pages/referentials/*",
"app/pages/reports/*"
]
}
};
System.config(config);
})(this);
However once I attempt to import my entry point from index.html, nothing happens (meaning I don't enter my then callback or my catch block). Here is an extract of my index :
<script src="#Href("~/wwwroot/app/middleware-app.js")"></script>
<script type="text/javascript">
System.import('app')
.then(app => {
console.log("never entered");
var endpoint = '#endpointUrl';
var version = '#Html.Version()';
var production = #Html.IsProductionEnabled();
app.run(endpoint, version, production);
})
.catch(function (err) {
console.log("never entered as well");
console.error(err);
});
</script>
I have tried various things like using bundleStatic instead, importing app/main.js, changing the bundling options.
Thank you for any help you can provide.
I assume that you are quite advanced and you have good angular2 understanding.
I had similar issue with #angular/upgrade component. After serious headache, I have found out that some of the error messages are lost inside angular2 (even in currently stable package).
The possible source of error can be inside #angular/compiler. The RuntimeCompiler.compileComponents() is losing messages from CompileMetadataResolver.getNgModuleMetadata(). Simple, yet not ideal solution is to wrap call to getNgModuleMetadata in try-catch block.
Solution when you are using bundled compiler and angular 2.0.0:
compiler.umd.js:line 16799
Change this:
RuntimeCompiler.prototype._compileComponents = function (mainModule, isSync) {
var _this = this;
var templates = new Set();
var loadingPromises = [];
var ngModule = this._metadataResolver.getNgModuleMetadata(mainModule);
ngModule.transitiveModule.modules.forEach(function (localModuleMeta) {
...
to:
RuntimeCompiler.prototype._compileComponents = function (mainModule, isSync) {
var _this = this;
var templates = new Set();
var loadingPromises = [];
try {
var ngModule = this._metadataResolver.getNgModuleMetadata(mainModule);
} catch(e) {
console.log(e);
throw e;
}
ngModule.transitiveModule.modules.forEach(function (localModuleMeta) {
...
Obviously, this is not ideal solution, but I was able to find out that one of my modules had circular dependency (which was causing undefined instead of valid service inside NgModule.import).

Angular 2 SFX production build

I have an Angular 2 Beta 8 (cannot update now) app that I need to bundle and minify for production deployment. With the following configs I can generate a SFX bundle but a minified version of the bundle does not work. It keeps on executing something and overflows the tab. I have component in it that has a console.log in in its constructor. That keeps running like more than 1000 times before the tab crashes. But the unminified version of the bundle runs as expected which is totally weird to me.
system.config.js
System.config({
defaultJSExtensions: true,
map: {
app: 'wwwroot/app/core',
angular2: 'node_modules/angular2',
rxjs: 'node_modules/rxjs',
dragula: 'wwwroot/lib/dragula/dragula.min',
'ng2-dragula/ng2-dragula': 'wwwroot/lib/dragula/ng2-dragula',
'ng2-cookies/ng2-cookies': 'wwwroot/lib/ng2-cookies/ng2-cookies'
},
packages: {
app: {
defaultExtension: 'js',
main: 'main.js'
},
angular2: {
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
}
}
});
gulpfile.js
function getBuilder(configPath) {
var builder = new SystemBuilder();
return builder.loadConfig(configPath)
.then(function () {
return builder;
});
}
gulp.task('bundle', function () {
return getBuilder('./system.config.js')
.then(function (builder) {
return builder.buildStatic('app', './bundledapp.js', { minify: true });
});
});
Any help is really appreciated.
Due to some bug in Angular 2 Beta versions a prod build was not possible

RequireJS - Issues loading Jquery and Jquery UI plugins

im new to requirejs and been loving it so far. I am in the process of implementing it to my existing project. I have a few jquery, Jquery UI and bootstrap plugins that all need to initialise at the start of the app.
I was hoping to put them all ligned up in a file called GDI_common.js and have it set in my main.js file in a require. When I load my page it seems to ignore my GDI_commons script. If I try to manually load the plugins via console they work fine.
I made sure that my dependencies are all correct and have what they need. Not quite sure what im overlooking at this point. Would anyone have any ideas or suggestions?
This is what my main.js file looks like:
require.config({
paths: {
"jqueryui": "../assets/jqueryUI/jquery-ui.min",
"bootstrap": "bootstrap.min",
"bootstrap_select": "../assets/silviomoreto-bootstrap-select-a8ed49e/dist/js/bootstrap-select.min",
"jqueryui_timepicker": "jquery-ui-timepicker-addon",
"jqueryui_timepicker_ext": "jquery-ui-sliderAccess",
"moment": "moment",
"cookie": "js.cookie",
"knockout-amd-helpers": "knockout-amd-helpers.min",
"text": "text"
},
"shim": {
bootstrap: {
deps : [ 'jquery'],
exports: 'Bootstrap'
},
bootstrap_select: {
deps : [ 'jquery', 'bootstrap'],
exports: 'Bootstrap_Select'
},
jqueryui_timepicker: {
deps : [ 'jquery','jqueryui'],
exports: 'JqueryUI_Timepicker'
},
jqueryui_timepicker_ext: {
deps : [ 'jquery','jqueryui'],
exports: 'Jqueryui_Timepicker_Ext'
}
}
});
require(["jquery","knockout", "XApplication", "Xcommon", "XButtons", "knockout-amd-helpers", "text", "moment"], function ($, ko, XApplication, GDI_common) {
ko.amdTemplateEngine.defaultPath = "../templates";
var viewmodel = new GDI_Application();
ko.applyBindings(viewmodel);
viewmodel.fetchdata();
});
This is what my my GDI_common file looks like:
define(["jquery", "jqueryui", "jqueryui_timepicker", "jqueryui_timepicker_ext", "moment", "bootstrap_select"], function($) {
//This loads the jqueryui_timepicker (jquery-ui-timepicker-addon.js) it needs jqueryui.
$('input[title^="Date de"]').datetimepicker({
addSliderAccess: true,
timeFormat: 'HH:mm',
dateFormat: "yy-mm-dd",
sliderAccessArgs: { touchonly: false }
});
//This loads the bootstrap-select plugin (bootstrap-select.min.js) it needs jquery and bootstrap.
$('.selectpicker').selectpicker();
//This is a jquery custom code that is used to calculate 2 fields upon clicking the .donne_moi_le_temps button.
$(".donne_moi_le_temps").click(function(){
updateDuration($('#DateDeDébut').val(), $('#DateDeFin').val());
function updateDuration(startTime, endTime) {
var ms = moment(endTime, 'YYYY/MM/DD HH:mm').diff(moment(startTime, 'YYYY/MM/DD HH:mm')),
dt = moment.duration(ms),
h = Math.floor(dt.asHours()),
m = moment.utc(ms).format('mm');
$('input[title^="Dur"]').val(h + ' heures, ' + m + ' minutes');
}
});
//This is loads the bootstrap tooltip function, this requires jquery and bootstrap.
$('[data-toggle="tooltip"]').tooltip();
//This is custom code and depends on the tooltip to be loaded first.
$(document).on('mouseenter', ".over_flow_control", function() {
var $this = $(this);
if(this.offsetWidth < this.scrollWidth && !$this.attr('title')) {
$this.tooltip({
title: $this.text(),
placement: "bottom",
container: 'body'
});
$this.tooltip('show');
}
});
});

jqGrid using requireJS - grid loads but does not work

I'm loading data into a jqGrid through requireJS, the data loads, formats and displays but after which nothing works, sorting, row selecting, paging etc. The grid works perfectly fine if I init the jqGrid without requireJS.
RequireJS config snippet :
"jqGrid": "jqGrid/jquery.jqGrid.min",
"grid-locale": "jqGrid/i18n/grid.locale-en", ...
shim: {
"jqGrid": ["grid-locale", "jquery-ui"]
}
JavaScript snippet:
define(["jquery", "httpUtils", "jqGrid"],
function ($, httpUtils, jqGrid) {
window.jqGrid = jqGrid;
var myViewModel = function () {
var data = httpUtils.httpSyncGet('xxx');
var grid = $('#index').jqGrid({
colNames: ['ClientIdentifier'],
colModel: [
{ name: 'ClientIdentifier', width: "150pt" }
],
datastr: data,
datatype: 'jsonstring',
rowNum: 25,
rownumbers: true,
height: 500,
viewrecords: true,
width: 1100,
shrinkToFit: false
});
};
return myViewModel;
});
Sorry if the code isn't very comprehensive I had to take out snippets from a large project. I'm just curious as to what causes the jqGrid to finish loading, but somehow 'unload' all of it's functions. There is no javascript error in the console as well.
I think you're missing some modules and dependencies. Here's what worked for me (and is also trimmed out from a larger project):
require.config({
baseUrl: "Scripts/TypeScript",
paths: {
jquerygrid: "../jquery.jqGrid.src",
jqueryui: "../jquery-ui-1.11.4",
jqgridlocale: "../i18n/grid.locale-en",
jqgrid: "../jquery.jqGrid.min"
},
shim: {
jqueryui: {
deps: ["jquery"]
},
uigrid: {
deps: ["jqueryui"]
},
jqgrid: {
deps: ['jqueryui', 'jqgridlocale']
},
jqgridlocale: {
deps: ['jqueryui']
}
}
});
I adapted the code above from this answer: requirejs jquery multiple dependent non module jquery plugins like jquery-ui and jqGrid , which addresses a more complicated scenario but my also be useful for you.

Categories