Arcgis conflict in Liferay 7.0 - dojo

I try to use Arcgis javascript API in Liferay 7.0 but it's fail. I think because Liferay 7.0 using requireJS for using javascript which conflict with dojo of Arcgis javascript API. I am using this code for implement Arcgis API:
<script type="text/javascript" src="<%=request.getContextPath() %>/js/arcgis_js_api/library/3.14/3.14/init.js"></script>
<script>
require([
"esri/map", "dojo/dom"
], function(Map, dom) {
var map = new esri.Map("map", {
basemap: "topo", //For full list of pre-defined basemaps, navigate to http://arcg.is/1JVo6Wd
center: [-122.45, 37.75], // longitude, latitude
zoom: 13
});
});
This is console log:
java.lang.IllegalArgumentException: Path esri/map.js does not start with a "/" character
java.lang.IllegalArgumentException: Path dojo.js does not start with a "/" character
This is javascript error:
Error: defineAlreadyDefined
Anyone has solution help me please. Thanks!

As you mention Liferay7 and your script tag makes use of <%=request.getContextPath()%>, you most likely have a mismatch between your portlet and the servlet API: request is not aware of any portlet context (but is still there, because JSPs have been designed for servlets and it's a mandatory object that's around, irritating a lot of people)
The URLs for your own Javascript files are just not relative to the context root, but Liferay makes them available on a different path. The easiest way, without messing around with this location, is to just mention the file you'd like to include in your portlet's configuration. In Liferay 7 OSGi portlet modules, it works like this (pseudocode, simplified)
#Component(
immediate = true,
property = {
"com.liferay.portlet.footer-portlet-javascript=/js/main.js",
"javax.portlet.display-name=My Portlet",
},
service = Portlet.class
)
In JSR-286 portlets packaged in WARs, you'd use the footer-portlet-javascript value in WEB-INF/liferay-portlet.xml.
Alternatively, use the header-* variant.
I personally prefer this way over memorizing how the path of resources is being constructed.

I use this code before implement arcgis (javascript):
if(typeof define !== "undefined" && typeof require !== "undefined"){
window.__define = window.define;
window.__require = window.require;
window.define = undefined;
window.require = undefined;}
It will be resolved.

Related

Vue.js including non-npm JavaScript library

I'm a total beginner with Vue.js and struggling to find the answer to what I feel is a fairly basic need.
I have a JavaScript library that cannot be installed locally and must be imported via script tag in the index.html file in the old-fashioned way:
<script src="https://foo.bar/scriptyscripts.js"></script>
This library has a bunch of methods in it that I need to use in various spots throughout my app, so it's not going to be a problem to load it globally. The issue I'm facing is that it's loading fine, but the methods are not being recognised in components.
I can use the methods and whatnot if I put them all in a script tag in the index.html however doing that rather defeats the whole point of having components.
Can anyone help me with the step that I'm missing to register all of the methods in this loaded js file so my components don't get mad?
Specifically, the script contains require.js and a collection of other things including JQuery.
Including the library makes the method 'require' available, which is used to load other modules on demand - the example being "js/qlik" in the below snippet. "js/qlik" loads JQuery and a stack of stuff associated with "qlik".
//async login method here. not relevant to this problem
login().then(() => {
require.config({
baseUrl:
(config.isSecure ? "https://" : "http://") +
config.host +
(config.port ? ":" + config.port : "") +
config.prefix +
"resources",
webIntegrationId: config.webIntegrationId,
});
//Load js/qlik after authentication is successful
require(["js/qlik"], function (qlik) {
qlik.on("error", function (error) {
$("#popupText").append(error.message + "<br>");
$("#popup").fadeIn(1000);
});
$("#closePopup").click(function () {
$("#popup").hide();
});
var app = qlik.openApp("caa866be-c8e1-44c8-b67b-dac9d24421fa", config);
});
});
The problem I have is that if I load this library in the index.html file and then try to execute the methods in the snippet above in any component, it does not know that the methods are available.
I see:
'Module not found: Error: Can't resolve 'js/qlik'
66:11 error '$' is not defined
which indicates that the components are unaware of the methods because they're not registered like they would be if I were importing a packaged afterinstalling it locally via NPM
i.e. Your original js code: function abc(){// sth...}
What you need: window.abc = ()=>{// sth...}
Even if you want it in Vue dom.
You should add vue.prototype.abc = ()=>{//sth...}

Multiple Aurelia Instances - Aurelia Webpack Plugin - aureliaApp option - "module not found"

I am composing my web app as a number of Aurelia "feature" apps - although I'm not using Aurelia features as such. Consequently in my html markup I have two entry points pointing to different apps:
<!-- Top Navigation Bar -->
<div aurelia-app="topnav"></div>
<!-- Main App-->
<div aurelia-app="main"></div>
I am using webpack and everything works perfectly using the single "main" app. Webpack generates a JS file "main.bundle.js" which I include in the src tag.
Things are not so straightforward when I added the "topnav" app. In webpack I tell the plugin to use a different aureliaApp name:
new AureliaPlugin({ aureliaApp: "topnav"}),
and, as you can see my HTML entrypoint also calls "topnav". Webpack generates a JS file "topnav.bundle.js" which I also include. I have a file called "topnav.ts" which contains the aurelia Cionfigure function which ends:
aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName("nav")));
And a pair of files "nav.ts", "nav.html" which constitute my viewmodel and view.
When I run the app aurelia loads and the "nav" module code executes. But I then get an error - see below.
The module which it reports that it cannot find is the one entered into the HTML markup.
Should this work? Have I missed something?
I should add, everything seems to work. I can create and update properties in the viewmodel and these are bound to the view. It's just that this error is thrown.
You are doing nothing wrong, just unsupported scenario. Per official doc-wiki: https://github.com/aurelia/webpack-plugin/wiki/AureliaPlugin-options#aureliaapp
You can have only 1 auto entry module with aureliaApp configuration. To solve this, you just need to add PLATFORM.moduleName('topnav') to your main.ts (and put it on root level)
Another way to do is to bootstrap manually:
// in your index.ts
import { bootstrap } from 'aurelia-bootstrapper';
// bootstrap top nav application, with one instance of Aurelia
bootstrap(aurelia => {
// do your configuration
aurelia
.start()
.then(() => aurelia.setRoot(
PLATFORM.moduleName('topnav'),
document.querySelector('#topnav')
);
});
// bootstrap main application, with another instance of Aurelia
bootstrap(aurelia => {
// aurelia.use.standardConfiguration();
// ...
aurelia
.start()
.then(() => aurelia.setRoot(
PLATFORM.moduleName('app'),
document.querySelector('app')
)
});

ArcGIS Api (Esri) triggering multipleDefine error

I have this weird issue while using ArcGIS API for JavaScript v4.4 in my code. I am trying to build an Excel Web Add-in in which I would like to load an ArcGIS map but when I load ArcGIS I get a multipleDefine error.
ArcGIS is getting bundled with Dojo which is used as the loader for all the ArcGIS/esri packages. I have no other choices to load my own custom JS bundles with Dojo because of the way ArcGIS has built their API. So I can't decide to not use Dojo and thus not getting the multipleDefine error.
I load my own JS files like this:
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js" type="text/javascript"></script>
<script>
var dojoConfig = {
parseOnLoad: false,
async: false,
// we make aliases for our js file
aliases:  [
['index',  './Bundles/index.js'],
],
};
</script>
<script src="https://js.arcgis.com/4.4/init.js"></script>
<script>
require(['index'], function (index) {
//...do something
});
</script>
When I restart the page I get a multipleDefine error once in every two/three trials. After a lot of investigation I understood that the error lies with the Office.js API but I had a hard time to find a good solution.
After a while I found the cause of the problem; we cannot start office-js and Dojo together because they both want to add scripts in the head tag of our page and somehow they end up in conflict with one another, thus we get the dreaded multipleDefined Dojo error and some of our files do not get loaded.
Once this cause was identified I decided to solve it by making sure Dojo, Argis and my custom js files got loaded once Office and dependencies were fully loaded.
I implemented it like this in my js code:
// This Dojo config variable has to be defined before Dojo is loaded in our scripts
var dojoConfig = {
// we make aliases for our custom js file
aliases: [
['index', './Bundles/index.js'],
],
// We require our dependencies (our own code bundles) with Dojo.
// Notice that it is mandatory to bundle our js files
// as AMD Modules for Dojo to be able to load them as dependencies.
deps: ['index'],
};
// Once office has fully initialized we can add our arcgis file and let
// him load our own required javascript files.
// We cannot start Office-js and Dojo/Arcgis together because they both
// want to add scripts in the head tag of the HTML page and
// somehow they end up in conflict, thus we get the dreaded
// multipleDefined Dojo error and some of our files
// do not get loaded.
Office.initialize = function (reason) {
// we manually add the Arcgis script to the header of our page
// once we are sure Office and dependencies has fully loaded.
var tag = document.createElement('script');
tag.src = 'https://js.arcgis.com/4.4/init.js';
document.getElementsByTagName('head')[0].appendChild(tag);
};
Once this was added the code started working like a charm.

Sometime getting file not found error for http://js.arcgis.com/3.9/js/dojo/jquery.js and ESRI map doesn't load

I'm using "js.arcgis.com/3.7" to implement esri maps. Sometime when i try to load page, I get below error and map doesn't load.
Error:
http://js.arcgis.com/3.9/js/dojo/jquery.js Failed to load resource: the server responded with a status of 404 (Not Found)
scriptError(…)(anonymous function) # init.js:40 (console.error(a))
Below is my code:
require([
"esri/map",
"esri/toolbars/draw",
"dojo/parser",
"esri/dijit/LocateButton",
"dijit/layout/BorderContainer",
"dijit/layout/ContentPane",
"dijit/form/Button",
"dijit/WidgetSet",
"dojo/domReady!"
], function (
Map,
Draw,
parser,
LocateButton
) {
parser.parse();
var opts = {
basemap: "topo",
center: [-103.08, 44.05],
zoom: 17
};
map = new Map("mapDiv", opts);
geoLocate = new LocateButton({
map: map
}, "LocateButton");
geoLocate.startup();
}
});
To clarify, you're using the 3.7 JS API, but are getting an error referencing the 3.9 API?
Moreover, is there a reason you're not using the newest (3.18) API?
I'd have to see a full stack trace, but it's difficult to see why Esri would be referencing a module from a newer version of its API. They've provided a resource for their 3.18 API on using jQuery with Dojo, if you decide to switch to the newest version:
https://developers.arcgis.com/javascript/3/jssamples/framework_jquery.html
That said, I don't see any references to jQuery in your code, so without more information I'd imagine the issue is a broken internal reference in their 3.7 API.

Simply cannot make SignalR (asp.net mvc4) and require.js work together

I've seen similar posts around the web and nothing anyone has suggested works for me. I'm really faced with the choice of dumping one or the other it seems at this point.
This "Getting Started with SignalR and MVC 4 tutorial":
http://www.asp.net/signalr/overview/getting-started/tutorial-getting-started-with-signalr-and-mvc-4
says you need two script includes to make signalR work:
<!--Reference the SignalR library. -->
<script src="~/Scripts/jquery.signalR-1.0.1.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="~/signalr/hubs"></script>
I'm at a loss as to how to make the second one, the autogenerated SignalR hub script, happen in require.js. Unless I'm missing something there just doesn't seem to be a viable require.js syntax for inclusion of autogenerated scripts. Without it you get this error at line 159 of jquery.signalR-1.1.2.js:
"JavaScript runtime error: SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. "
The code at that point in jquery.signalR is doing this:
signalR.hub = {
start: function () {
// This will get replaced with the real hub connection start method when hubs is referenced correctly
throw new Error("SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/hubs'></script>.");
}
};
Has anyone actually made this autogenerated script thing happen via require.js?
Been studying this a bit more. Let me add some detail:
I'm using this approach - Structuring scalable client side applications: (http://johndavidmathis.wordpress.com/2013/04/23/structuring-scalable-client-side-applications/) to make a more scalable structure. Second part in that series "Permit modules to utilize multiple files and a logical folder structure" http://johndavidmathis.wordpress.com/2013/04/23/structuring-scalable-client-side-applications/ has me splitting my actual signalr code out into a separate Marionette chat module (separate from my main app.js file) to achieve a better file structure. I really like this approach. The rest of my project is set up like this now and it really is showing benefits when it comes to finding code. I think that extra split is where I'm stuck. Can't seem to get that second dependency, the autogenerated script, into that separate chat module file. I'm still studying this but it looks like this to me at this point. require.js gets the dependency into my Marionette app:
require(["marionette","handlebars", "signalr", "signalr.hubs"], function (Marionette) {
window.App = new Marionette.Application();
App.addRegions({
headerRegion: "#header",
contentRegion: "#content",
footerRegion: "#footer",
});
require(["modules/main/loader", "modules/chat/loader"], function () {
App.start();
});
})
If I want chat that dependency to make its way further into the app, into the chat module in another file?
Something like?
define(dependencies,
function () {
App.module("ChatModule", function (ChatModule, App, Backbone, Marionette, $, _, "signalr.hubs", "signalr.hubs") {
// SignalR Proxy created on the fly
var chat = $.connection.chatHub;
// Start the connection
$.connection.hub.start();
//more chat code...
An update:
The answer below does work in my dev environment. But it does not work when I publish the code to a real production server.
When the code is published to a real production server (IIS 6.1 on Windows Server Enterprise 2008 R2) the browser console once again shows a "404" for the autogenerated reference.
Specifically, the console shows the "?" is being added into the reference path before ".js", like this...
http://mydomain.com/myapp/Scripts/application/signalr/hubs?.js...
Tried taking the "?" out but then it removes my app name from the path, like this...
http://mydomain.com/signalr/hubs.js.
I think what would get me there is the first one, without the "?", like...
http://mydomain.com/myapp/Scripts/application/signalr/hubs.js
I'm just not seeing how to make that happen.
FINAL UPDATE:
Final piece of the puzzle for production server is the site's virtual directory. Here's final code that worked for me. Thanks Raciel R for your help:
requirejs.config({
paths: {
//core
"jquery": "jquery-1.9.1",
"signalr": "jquery.signalR-1.1.2",
"signalr.hubs": "/productionservervirtualdirectory/signalr/hubs?"
},
shim: {
"jquery": {exports: "$"},
"signalr": { deps: ["jquery"] },
"signalr.hubs": { deps: ["signalr"] }
});
//Then all you have to do is to make signalr.hubs required in your modules. Ie:
require(["signalr.hubs"], function(){
//your code here
});
requirejs.config({
paths: {
//core
"jquery": "jquery-1.9.1",
"signalr": "jquery.signalR-1.1.2",
"signalr.hubs": "/signalr/hubs?"
},
shim: {
"jquery": {exports: "$"},
"signalr": { deps: ["jquery"] },
"signalr.hubs": { deps: ["signalr"] }
});
Then all you have to do is to make signalr.hubs required in your modules. Ie:
require(["signalr.hubs"], function(){
//your code here
});
I set up RequireJS successfully using #raciel-r's solution but I was still having problems with other JavaScript modules like karma that were also confused by the dynamic proxy. I converted the signalr proxy to a static file and used that with RequireJS instead:
Import Microsoft.AspNet.SignalR.Utils
Run packages/Microsoft.AspNet.SignalR.Utils.2.X.X/tools/signalr.exe
ghp /path:my/bin /o:path/to/scripts/server.js where /my/bin is the directory containing the assemblies with your SignalR Hubs.
Replace your reference in to /signalr/hubs with server:
requirejs.config({
paths: {
// ...
"signalr.hubs": "path/to/scripts/server"
},
// ....
If you are using the convenience methods of the generated proxy, you will also have to rewrite them (see How to create a physical file for the SignalR generated proxy)