I need to design how to implement JavaScript module pattern in existing large .NET Web Forms application. Currently there are no rules and lot of JavaScript code uses global variables. The problem is also with communication between server and JavaScript client code, currently lot of JavaScript functions are called from code-behind classes and are inlined into page.
Current JavaScript usage example
A server control adds link to some JavaScript file to the <head> element so it will be downloaded. The file contains one or more global functions. Then the server control call's this global functions whenever it needs them, like following:
string script = string.Format("GlobalFunction1('{0}');", param);
And this string is inserted somewhere inside the <body> element in the HTML. There are no rules and the server can call any of the global function whenever it needs them.
The main goals for improvements are:
Separate server-side code from client-side JavaScript. This means no chaotic inline calls for JavaScript global functions.
JavaScript self functioning modules, which are not dependent on each other.
JS modules should not expose anything to global scope.
Every JS module has only one place to initialize itself.
Server-side should be able to populate some parameters to JS module initialization.
Here is the approach that I came with:
How would it look like on Server-Side
Every Control has its own JavaScript module
Every Control is wrapped inside its root <div> element.
Server can call this helper method in every page life-cycle: ScriptModule.AddParam("param_name", "param_value"); This params will be added to the Control's wrapper (div) on pre_render event call as HTML5's data- attributes.
Finally Server registers the module with ScriptModule.Register("module_name", "path_to_js_file", "controlWrapperId").
This results in these steps in HTML:
The <script> file (path_to_js_file) is inserted into the page which links to desired module's file.
The parameters are added into Control's wrapper (div) through data- attributes.
At the end of the page the inlined Core.start("module_name", "controlWrapperId"); is inserted, which starts the module's initialization. This method is discussed later in client-side section.
How would it look like on Client-Side
The first file that is downloaded is the Core.js file, which registers one global variable Core that is used to define new modules.
Every JavaScript file will be defined as module. This module should not expose anything to the global scope and should be self functioning. The template follows:
// 1. first param is module's name
// 2. than the array with dependencies to helpers modules
// 3. than the callback with following parameters
// a. jQuery object which references wrapper (i.e. div) of this module
// b. params hash-object, which contains server parameters from wrapper's -data attributes in format
// { 'param1_name': 'param_val',
// 'param2_name': 'param2_val' }
// c. then the external dependencies to helper modules
Core.htmlModule('mod name', ['external', 'deps'], function ($w, params, external, deps) {
// Here the module initializes itself
// it can communicate with other modules through Core.publish(); Core.subscribe();
// it does not return anything, because it is HTML module and so it does not expose anything
});
The second parameter defines so-called helper modules, which are for code reusing. Due to the normal module's independence and inability to expose some functions outside, there is needed something to share same code. This can be achieved by defining helper module, which can expose some of its properties and then be referenced from normal module.
Related
I am wondering if all asynchronous events and callbacks can be traced back to a specific source component by wrapping all component logic (including logic of non-component directives inside component) in a zone, then only that source component needs to be checked for changes along with any child components with changed inputs from the source component, assuming all changes are following the uni-directional flow.
Is this understanding sound?
Is this change detection strategy available in Angular2?
Why is Angular2 detecting changes on all the components after any asynchronous (XHR) event?
One whole Angular application runs in a single zone. Angular uses the zone to patch async APIs and uses notifications from these patched APIs to run change detection every time some async event happened.
The uni-directional flow is for [prop]="value" bindings that works only from parent to child.
Angular runs change detection from root to leafs.
If ChangeDetectionStrategy.OnPush is configured for a component, change detection skips these components (and their descendants) until some binding (inputs) have changed.
There are other strategies to optimize CD.
For example observables and promises, that actively notify about changes and don't need change detection.
Immutable objects which are guaranteed to not change their propery values.
Update
Angular doesn't know what values an event handler has changed. Properties of a component, of a global service, of object references that were passed around, .... It just assumes that when an event handler was called that probably something has changed and then runs a complete change detection cycle to propagate all bindings from parent to child.
Child do parent bindings are events anyway and therefore aren't updated during change detection.
... by wrapping all component logic (including logic of non-component directives inside component) in a zone, then only that source component needs to be checked for changes along with any child components with changed inputs from the source component, assuming all changes are following the uni-directional flow. Is this understanding sound?
When an template-bound event fires – e.g., (click)="doSomething()" – the doSomething() method is free to alter any component or application data. Template statements, such as our doSomething() event handler, are not bound by the unidirectional flow rule, as per the Angular docs:
Responding to events is the other side of Angular's "unidirectional data flow". We're free to change anything, anywhere, during this turn of the event loop.
This is why, by default, Angular's change detection has to check every template binding in every component after an event fires. (Well, after an event within the Angular zone fires.) Angular doesn't know what might have changed... it has to discover what has changed.
The unidirectional flow rule applies to template expressions such as {{some expression}} or [childInputProperty]="parent expression" or if you implement an input property setter method: #Input() set childInputProperty(variableName:type) { ... }.
Is this change detection strategy available in Angular2?
No, because it would severely limit what an event handler could do. Dirty-checking every template binding may not be the most efficient way to detect changes, but it makes it much easier for us to write our event handlers (i.e., to write our applications).
Why is Angular2 detecting changes on all the components after any asynchronous (XHR) event?
Angular doesn't want to limit what we can do in our event handlers. An event handler bound in ComponentA's template can change data that is local to ComponentA, but it can also change data that is in a service (and hence it can change data that is visible to other components), and it can change data in other components, e.g., by calling public APIs/methods on other components.
Struggling here with what would otherwise be a simple $( document ).ready().
Not sure what I'm doing wrong.
Materialize needs jquery components to be initialized on DOM ready. Finding a way to initialize components on all views is surprisingly tricky.
Here is the online DEMO
From reading the docs: this should initialize everything the sub-templates require:
Template.layout.rendered = function(){
$('ul.tabs').tabs()
}
}
However, this only works on a hard page refresh, and not with links routing the views.
So instead you would have to initialize on each template that element will be used
Template.x.rendered ...
Template.y.rendered ...
Here is the github code
BTW We've tried iron-router events:
onRun
onBeforeAction
onAfterAction
All of these seem to happen before the route's template content is present. I noticed that onBeforeAction required a call to this.next() to go on, I even tried looking for the DOM content after the next call.
I also tried rewriting our routes like this:
Router.route('someRoute', function() {
this.render('someRoute');
// look for DOM content, still not found
});
Just to be clear, the reason this is happening is because your layout is only firing the rendered hook once. When you switch routes the layout template will not be rerendered, only the templates in the yield region will be. The previous template in that region gets destroyed and the next one rerendered. This means you have to run $('ul.tabs').tabs() again for that Template as the DOM elements it contains are rerendered.
Putting that code in the rendered function of the template that uses it works because that rendered hook gets run every time that particular template gets rendered again.
A way you could get around this could be to create a Template specifically for your tabs, like a control in a way, that calls $('ul.tabs').tabs() in its own rendered function. You could then put this control on a template that needed it and pass the required arguments, like number of tabs and content for each tab etc. It's a bit of work though, and I'd only consider it if I had a really large number of templates that used the tab control.
Here is the situation :
On a MVC application I have a partial that is rendering a script bundle.
this partial is rendered several times.
Is there a built-in way to determine an specific Bundle is rendered before in some place on page ?
Thanks professionals
Update : here is the code for clearing the condition
main layout :
<html>
<body>
#if(someCondition){
#Html.RenderPartial("SamePartial")
#Html.RenderPartial("SamePartial")
#Html.RenderPartial("SamePartial")
}
</body>
</html>
and this is inside partial :
<div>Blah Blah Blah</div>
#Scripts.Render("~/bundles/JusNeededInsidePartial")
#Styles.Render("~/Themes/styles/JusNeededInsidePartial")
partial is rendered several times. I need a way to render bundles 1 time only
Define a Razor section:
#section MySpecialScripts {
#Scripts.Render("~/bundles/MySpecialScriptsBundle")
}
in views where you need such scripts and add the following to the main layout:
#if (IsSectionDefined("MySpecialScripts")) {
RenderSection("MySpecialScripts")
}
I'd be a bit leery about putting bundles inside your partial views like you are doing.
For best performance, I'd suggest putting scripts at the bottom of your page (ref: http://developer.yahoo.com/blogs/ydn/high-performance-sites-rule-6-move-scripts-bottom-7200.html)
If your bundles contain stylesheets, you're going to be putting them in the body, which is still valid, but I like to organize them so that they're all together.
Typically what I would do is add this to my _Layout.cshtml right before the closing </head> tag:
#RenderSection("Head", required: false)
Then, in my View, I could have:
#Html.RenderPartial("SamePartial")
#Html.RenderPartial("SamePartial")
#Html.RenderPartial("SamePartial")
#section head{
#Scripts.Render("~/bundles/myBundle")
}
And if I wanted to do something similar on another View:
#Html.RenderPartial("OtherPartial")
#Html.RenderPartial("OtherPartial")
#section head{
#Scripts.Render("~/bundles/myOtherBundle")
}
I know this is a bit different than what you were asking for, but I think there's value in the flexibility of this solution.
And if you're loading things dynamically, you could always put a simple condition in your section:
#section head{
#if(SomeCondition){
#Scripts.Render("~/bundles/modernizr")
}
}
You can do the check in the JavaScript scripts themselves:
In JavaScript you can check if something has been previously defined, and only define it if it hasn't.
For example:
if (typeof flag === 'undefined') {
// variable is undefined
flag = {};
// Here type the code that must happen only once
}
NOTE: the flag name is a global var. To avoid collisions, you'd "namespace", and use specific names for each script file like this:
if (typeof myScripts === 'undefined') {
myScripts = {};
}
if (typeof myScripts.MySpecialScripts=== 'undefined')
{
myScripts.MySpecialScripts = '';
// Add the "MySpecialScripts.js" code here
}
However, I'd render the script bundle outside the partials to ensure it's available to them. In this way you can ensure that it's rendered only once and available to all your partials.
In fact, unless it's a very large .js file, why not include it in your general bundle?
Yep, I know you feel tha your project is "better organized" if you include the scripts on the view which needs them, but that's not a good idea: you have to control if they have yet been included or not, you cand' move them to the bottom of the page if you want to and so on.
If you still want to keep your original idea you can use a the client dependency framework. It's not exactly what you want to do, but it's the best available solution. When you use this framework, you need to declare the dependencies of you components (Views) using different methods, like this:
#{Html.RequiresJs("~/myscript.js");}
Anyway, as I wrote in my comment, the problem with this kind of solution is that if you start using AJAX there is no single way to get sure that you always get the desired scripts, and that they are available on client side when you need them. Unless you use some variation of the first client-side solution that I wrote in this answer (there are better solutions based on this basic concept). Let me insist: the best solution is always to have everything ready on the client side (unless it's a really huge project that have hundreds of big js files). Remember that the js file is loaded once, and cached for later use in the browser, so downloading a big .js file it's not such a big problem.
And please, even if you think you need a server side solution, don't discard a client side solution. Remember that, even if you server the js from the server, that's 'client side' code, so, why not use a 'client side solution' for your 'client side code' problem?
Still anothe solution: ypu can use PageData to share information between views, layouts, and partial views. When you need to add a script in any of this places, use a flag in PageData. If the flag is not present, render the script, and set the flag. If the flag is present, don't render the script. In this way, the script will be rendered only the first time.
if (PageData["JusNeededInsidePartial"] == null) // Check the flag
{
#Scripts.Render("~/bundles/JusNeededInsidePartial");
PageData["JusNeededInsidePartial"] = ""; // Set the flag
}
The problem with AJAX still exists, because if you render the partial by AJAX, it will load the script in the client side everything the partial view is loaded by AJAX.
I am going to use either knockout.js or angular.js libs (b/c of the binding support) for a web app.
My question is - how is your experience integrating these libs into existing UI libs like Dojo, jQueryUI, Ext.js, YUI,..
E.g. how is the usage of databinding suport/syntax in the UI libs? Do you have to implement something like custom binding in order to use the widget form UI lib?
For Knockout the situation is quite good. One can integrate with third-party widgets via custom bindings. Bindings API is very simple and strait-forward. All you need is to implement one or two methods (quoting Knockout docs):
ko.bindingHandlers.yourBindingName = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
// This will be called when the binding is first applied to an element
// Set up any initial state, event handlers, etc. here
},
update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
// This will be called once when the binding is first applied to an element,
// and again whenever the associated observable changes value.
// Update the DOM element based on the supplied values here.
}
};
Most of the time implementing single update method is sufficient. There's even a collection of ready-made bindings for jQuery UI. It doesn't cover all jQuery UI widgets but since creating custom bindings is so simple you can implement your own bindings as you see need.
As for Angular JS the situation is more difficult. You can create a custom binding as a part of your own Directive. Directives API requires you to write much more code. The lifecycle of directives is quite complex, too. So, they would take quite a bit of time to learn.
At the same time it lets you specify a lot of different aspects of behavior. For example you can completely rewrite the inner HTML representation of a widget via directive and use Angular templates inside. In Knockout you'd need to use jQuery for that. Unfortunately, unlike custom bindings in Knockout directives are more suitable for writing your own widgets and not for integrating with existing ones.
To summarize:
Knockout bindings are easier. Integrating with third-party widgets is easy.
Angular directives are more suitable for writing your own widgets but are more powerful at the same time.
Typically you would implement custom bindings to work with external libraries, but there are often plenty of open source efforts that have already made considerable headway. Check out
https://github.com/SteveSanderson/knockout/wiki/Bindings
If there aren't any available, implementing your own isn't terribly complicated:
http://knockoutjs.com/documentation/custom-bindings.html
I am working on a small AIR desktop application and I have some configuration infos that I want to store in a little file that's loaded at some point when the application starts and will be used to set public properties on the root application object. This should work just as if I had public variables declared in an <mx:Script> block at the beginning of my main MXML file.
I seem to have the choice of three events that could be used to initiate loading the configuration file:
invoke
initialize
creationComplete
Did I overlook some more? Which one is appropriate and why? Does it matter at all?
Example issues that come to my mind are:
are all components already accessible or will I get NULL references?
will some of my settings be overwritten in a phase that's coming after the event?
There's probably more.
If your handler needs to access UI components directly, you should wait for creationComplete; otherwise you'll get NULL references.
If you simply want to set properties on the root Application object, initialize seems the best place to do this. If you wait until creationComplete, and if the properties that you set are bound to your controls, then you might get a run-time resize or flicker as those components are updated.