Proper way to move multiple .js includes into one include? - javascript

I have 2 Razor .cshtml files that have a similar structure like the following:
<script type="text/javascript" src='#Url.Content("~/Scripts/jqwidgets/jqxcore.js")'></script>
<script type="text/javascript" src='#Url.Content("~/Scripts/jqwidgets/jqxdata.js")'></script>
<script type="text/javascript" src='#Url.Content("~/Scripts/jqwidgets/jqxbuttons.js")'></script>
...
<More header stuff (different in both files)>
<script language="javascript" type="text/javascript">
function commonFunctionForJqWidgets() {
...
callSomethingFromJqWidgetsLibrary();
...
}
</script>
I am writing common code for these 2 files and would like to put the common code in another .js (or .cshtml) file instead of duplicating it in both places. However, the common code requires including some of the jqwidgets includes since it calls library functions for it.
What would be the proper way to handle this? Should I simply add a new .cshtml file, move all of the includes in there, and then define my common functions in there as well?

Usually when you have common UI code, you may put that inside a partial view which can be included in other views as needed. But in your case, It is more like a bunch of javascript files you want in multiple files. So you may create a script bundle which will have all those scripts and use that in your pages as needed.
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
// Your existing bundles here
bundles.Add(new ScriptBundle("~/bundles/jQxWidgets")
.Include(
"~/Scripts/jqwidgets/jqxcore.js",
"~/Scripts/jqwidgets/jqxdata.js",
"~/Scripts/jqwidgets/jqxbuttons.js",
"~/Scripts/SomeOtherCustomJsfileRelatedtojQxWidgets.js"));
}
}
And in your specific views, you can include this inside the Scripts section.
#section Scripts
{
#Scripts.Render("~/bundles/jQxWidgets")
}
Or if you have more than just the scripts as your common stuff, create a partial view and include your common stuff there and include this partial view in your other views as needed.
Create a partial view called CommonGrid.cshtml inside your ~/Views/Shared folder
<h2>Common header for both the pages </h2>
#section Scripts
{
#Scripts.Render("~/bundles/jQxWidgets")
}
And in your other views
UserList.cshtml
<h1>Users</h1>
#Html.Partial("CommonGrid")
ProductList.cshtml
<h1>Products</h1>
#Html.Partial("CommonGrid")
You can also make your CommonGrid strongly typed to a view model and create a property in your page specific view model of this type(of CommonGrid's viewmodel) and pass that in the Html.Partial method.

Related

Ads with script tags in template [Vue.js]

In our project we've previously been using Thymeleaf, but now that we're moving over to Vue.js, we're experiencing some issues using the same ad scripts. The scripts look like this. I've only altered the URLs.
<script data-adfscript="sub.adcompany.net/asdf/?id=256746"></script>
<script src="//sub.adcompany.net/url/to/advertisement/script.js" async="async" defer="defer"></script>
If we put these tags in the <template>, Webpack gives the following message:
Templates should only be responsible for mapping the state to the UI.
Avoid placing tags with side-effects in your templates, such as
, as they will not be parsed.
So I've then been Googling all over to find a similar case. There are some plugins that do this for Google Ads, but they won't work for us. Escaping the script tags <\/script> works in a way, but then the script isn't added to the DOM until after loaded, and so it doesn't run.
Has anyone run into similar issues? If so, what was your solution?
Vue file looks something like this:
<template>
<aside class="sidebar-ad ui-wide">
<script data-adfscript="sub.adcompany.net/asdf/?id=256746"></script>
<script src="//sub.adcompany.net/url/to/advertisement/script.js" async="async" defer="defer"></script>
</aside>
</template>
<script>
export default {
data () {
return {}
}
}
</script>
There is a workaround. Works with style tag too.
<component is="script" src="https://www.example.com/example.js" async></component>
You should not treat Vue templates as a your final HTML, although their syntax is nearly identical and is also HTML-syntax compliant.
Templates are just a UI scaffolds for the data (that is why it is called a data-driven paradigm). They get parsed and transformed into render functions that in the end will produce the final and reactive DOM tree. During this process the <script> tags are indeed ommited cause it is not a place for any logic to happen.
However if you really need to embed any 3rd party script within your component there is a neat way to do this.
First, create container for the script:
<template>
<div id="component-root">
<!-- (...) -->
<div v-el:script-holder></div>
</div>
</template>
Then dynamicly create <script> tag and insert it directly to the DOM tree (using pure Vanilla JS):
<script>
export default {
data () {
return {};
},
ready() {
let scriptEl = document.createElement('script');
scriptEl.setAttribute('src', 'https://cdn.com/somescript.js');
scriptEl.setAttribute('data-some-param', 'paramvalue');
this.$els.scriptHolder.appendChild(scriptEl);
},
}
</script>
The this.$els.scriptHolder returns actual DOM element, calling the appendChild() forces the browser to insert DOM node and run the script just like during ordinary HTML code rendering.
Instead of $els you could also use $el which would return the components root DOM element (in this example the <div id="component-root">) or even the $root.$el which would return the Vue App root DOM element.
Note that this.$els is a Vue 1 feature, which has been replaced with $refs in Vue 2: https://v2.vuejs.org/v2/guide/migration.html#v-el-and-v-ref-replaced
You can try with this package
https://www.npmjs.com/package/vue-script2
I made a vue component to handle script loading within the template tags.
Personally, I use it to load ads in my vuejs apps.
here:
https://github.com/TheDynomike/vue-script-component
I found a way to work around this, not sure how well it works but this the way I did it.
Run the <script> in normal html then go to Dev tools and copy the iframe code made by the script and then paste it into the code as iframe instead of the <script>.
just place your in vue template scripts after your app, in exemple at the end of the body
(function($) {
$('#your-app').find('script').appendTo('body')
<script> your vue script (create app)</script>
})(jQuery);

How to add javascript widgets in BIRT reports

I am trying to extend BIRT for include a Report Item that is based on a javascript widget. I am not able to figure out how to include the js files used by a widget in the reportitemPresentation. I went through the 'RotatedText' example and tried to override the onRowSets method:
public Object onRowSets( IRowSet[] rowSets ) throws BirtException
{
StringBuffer str = new StringBuffer();
Str.append("<script type="text/javascript" src="../../scripts/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="../../jqwidgets/jqxcore.js"></script>
<script type="text/javascript" src="../../jqwidgets/jqxbuttons.js"></script>">);
.....//added code to initialize the widget.
return str.toString();
This added the script in the body of HTML but did not execute. Please ignore the syntax errors as the script tag was correctly added in the HTML.
In addition, I also want to add the code to initialize the widget:
$("#jqxbutton").jqxButton({ width: '150', height: '25'});
How do I do the following:
Include the js files of a widget in the html head tag.
How to include the code to initialize the widget and set some properties for the widget. For eg. How can I add the code for
$(document).ready(){ // initialize the widget, add some properties};
What classes do I have to extend, which method to override? Any examples would be helpful. What is the right way to include the widget?

Including Page Specific Assets

Using the Grails asset-pipeline plugin, I'm trying to figure out the best way to include assets (javascript) on a page versus having them compiled into the application.js file. Currently, this is what I'm doing...
At the bottom of my layout file:
<g:set var="workflow" value="${pageProperty(name: 'meta.workflow')}"/>
<asset:javascript src="application.js"/>
<g:if test="${workflow == 'storeAdmin'}">
<asset:javascript src="store/script.js"/>
</g:if>
In views/store/index.gsp header:
<meta name="workflow" content="storeAdmin" />
While this works, it feels like a hack. The reason I have to do it like this is because if I simply try and include the asset in the view itself, instead of the layout, it always gets rendered before the application.js, which means anything in that script that depends on global code will fail; code that requires jQuery for example.
I typically use a convention for naming page specific javascript assets that reflects the name of the controller and action. Using these and the <asset:assetPathExists> tag I can just add the following into my layout:
<asset:assetPathExists src="${params?.controller ?: 'home'}_${params?.action ?: 'index'}.js">
<asset:javascript src="${params?.controller ?: 'home'}_${params?.action ?: 'index'}.js" />
</asset:assetPathExists>

Javascript single page architecture with module autonomy

I just started this HTML5 project where we decided to make it a single page architecture by leveraging jQuery $.load() method. Unfortunately, as soon as the JS started to grow, we quickly started running into issues where the modules loaded into the master dashboard have no knowledge of their parent.
The architecture looks like this:
dashboard.html (master file)
moduleA.html
moduleA.js
moduleB.html
moduleB.js
moduleC.html
moduleC.js
Since we decided to also keep the JS as separate files, we are having to load all JS files through dashboard.html in order to invoke them individually when modulex is loaded.
So when loading moduleA.html into the dashboard we have to call its corresponding JS. To do this we simply wrote the JS using a Module Pattern so we can easily invoke it by doing a function call, like:
<script>
moduleA
</script>
or this if we want to access a specific property of this member.
<script>
moduleA.someMethod();
</script>
Now, I know there are is gotta be a nicer way of doing this, right? I hate having to have script tags in the HTML modules in order to load its corresponding JS file.
Another limitation of this is the fact that we no longer can work on modules individually, since the scripts and CSS invocation happens on the parent (dashboard.html) so certainly when moduleA.html is loaded directly, it is pure HTML with no script or CSS.
I looked through the other questions but I didn't see anyone with the same problem.
I looked at AngularJS, EmberJS, KO.JS and BoilerPlateJS but none of them addresses what we are trying to accomplish. The only one that has a similar single page concept is jQuery Mobile but I don't know if you can switch from jQuery to jQuery Mobile and everything remains working.
Has anyone face this issue yet? Is there a solution or would I have to go with a custom solution.
Thanks!
I could argue about AngularJS with you. It is exactly what you need
dashboard.html is layout with some directives attached, but power lies in AngularJs if you use ng-view directive
here is example:
dashboard.js
var app = angular.module("modularApp",[]);
app.config(['$routeProvider', "$locationProvider", function routes($routeProvider, $locationProvider) {
$routeProvider.when('/dashboard', {
controller:'HomeCtrl',
templateUrl:'templates/home.html'
});
$routeProvider.when('/moduleA', {
controller:'ModuleACtrl',
templateUrl:'templates/moduleA.html'
});
$routeProvider.when('/moduleB', {
controller:'ModuleBCtrl',
templateUrl:'templates/moduleB.html'
});
$routeProvider.otherwise({redirectTo: "/dashboard"});
}]);
templates/dashboard.html
<html ng-app="modularApp">
<head>
<!--.... include angular minified js file and what else you need...-->
<script type="text/javascript" src="dashboard.js"></script>
<script type="text/javascript" src="moduleACtrl.js"></script>
<script type="text/javascript" src="moduleBCtrl.js"></script>
</head>
<body>
<a ng-href="#/moduleA">Open Module A View</a>
<a ng-href="#/moduleB">Open Module B View</a>
<!-- Add widgets header menus .... -->
<ng-view></ng-view>
</body>
</html>
moduleACtrl.js
var app=angular.module("modularApp");
app.controller("ModuleACtrl",function($scope){
$scope.scopeValue="Hellow from view";
});
moduleBCtrl.js
var app=angular.module("modularApp");
app.controller("ModuleBCtrl",function($scope){
$scope.scopeValue="Hellow from another view";
});
templates/moduleA.html
<div>{{scopeValue}} in module A</div>
templates/moduleB.html
<div>{{scopeValue}} in module B</div>
You can do more complex things with angular then just this. All depends on your needs. Do you have any special requirements :)
Also, you could create your own directive, like ng-view and use your own $route service and $routeProvider so you can add css and javascript you want to dynamically load when some rute match url.
so instead of above routing table, you could have
app.config(['$myRouteProvider', "$locationProvider", function routes($routeProvider, $locationProvider) {
$routeProvider.when('/dashboard', {
javascript:'javascript/dashboard.js',
templateUrl:'templates/dashboard.html',
cssfile: 'css/dashboard.css'
});
$routeProvider.when('/moduleA', {
javascript:'javascript/moduleA.js',
templateUrl:'templates/moduleA.html',
cssfile: 'css/moduleA.css'
});
$routeProvider.when('/moduleB', {
javascript:'javascript/moduleB.js',
templateUrl:'templates/moduleB.html',
cssfile: 'css/moduleB.css'
});
$routeProvider.otherwise({redirectTo: "/dashboard"});
}]);
But that is, pardon on my French, stup. There are couple libs I tried in ruby on rails to acheive similar, but backend is rendering content, or just part of content. But I'm not sure which backend you are using and are you interested to switch to rails anyway.
DomController in BoilerplateJS does what you need, without using any custom HTML attributes. Your dashboard.html can just have place holders where you want to inject your components. I'm just pulling out some html below from BoilerplateJS index.html to show how it works:
<body>
<section id="page-content">
<header>
<section class="theme"></section>
<section class="language"></section>
</header>
<aside>
<section class="main-menu"></section>
</aside>
</section>
</body>
theme, language and main-menu sections above are just place holders in to which relavant components would be injected by the DomController. The DomController can be now used to register the components with appropriate selectors as below:
//scoped DomController that will be effective only on $('#page-content')
var controller = new Boiler.DomController($('#page-content'));
//add routes with DOM node selector queries and relavant components
controller.addRoutes({
".main-menu" : new MainMenuRouteHandler(context),
".language" : new LanguageRouteHandler(context),
".theme" : new ThemeRouteHandler(context)
});
controller.start();
Above code is extracted from "/boilerplatejs/src/modules/baseModule/module.js"

I want to include everything from my main page except one js file ..

I have a use case in which i want to include my main.gsp file in my page list.gsp , that is easily achieved by doing
<meta name="layout" content="main"/>
But the problem is that it has jQuery 1.6 version but i want an alternative to that a file called as jquery.js and i when i am including it as well in addition to the main layout its conflicting and creating a problem ..
like
<script type="text/javascript" src="${resource(dir: 'js/jquery', file: 'jquery.js')}"></script>
The above is not working , so what i have thought is either manually differentiate the files to be included on my list.gsp page or is there a way to include everything that is on main.gsp page except this jQuery1.6.js file ??
I am open to any other suggestions..
Thanks in advance
A dirty method could be to put the script import in a if block that checks for a page property, and in your list.gsp set that property.
In list.gsp:
<body fooProperty="1">
And in main.gsp:
<g:if test="${pageProperty(name:'body.fooProperty) ?: false}">
<%--includes you want for list.gsp here--%>
</g:if>
<g:else>
<%--normal script link -%>
</g:else>
Forces a if/else on every single page load you got, but there isnt many other ways to do it. Might be to set a hidden page property and write a loader that overrides the 1.6 import in javascript itself.
Put in your main.gsp
${if(!params.jqueryVersion) params.jqueryVersion=''}
<script type="text/javascript" src="${resource(dir: 'js/jquery', file: 'jquery${params.jqueryVersion)}.js')}"></script>
and in your list controller return
[myInstancesList:list, jqueryVersion:'-1.4.2']

Categories