Cordova on WP8: requirejs can't resolve views - javascript

I have a web application that uses requirejs to load its modules. The web applications works without problems in any desktop browser, it also works on iOS and Android when packaged with Cordova. Does however NOT work when building a Windows Phone 8 Cordova application.
I get the following error:
"View Not Found: Searched for "views/shell" via path "text!views/shell.html"
(I'm using Durandal)
I have the following application structure:
lib/require/require.js
www/app/viewmodels/shell.js
www/app/views/shell.html
www/app/main.js
www/index.html (contains line: )
:
www/app/main.js contains the following code:
requirejs.config({
//baseUrl: 'x-wmapp0:www/app',
baseUrl: 'app',
enforceDefine: true,
paths: {
'text': '../lib/require/text',
'durandal':'../lib/durandal/js',
'plugins' : '../lib/durandal/js/plugins',
'transitions' : '../lib/durandal/js/transitions',
'knockout': '../lib/knockout/knockout-2.3.0',
'bootstrap': '../lib/bootstrap3/js/bootstrap',
'jquery': '../lib/jquery/jquery-1.9.1',
'modules' : 'modules'
},
shim: {
'bootstrap': {
deps: ['jquery'],
exports: 'jQuery'
}
}
});
define(['durandal/system', 'durandal/app', 'durandal/viewLocator', 'bootstrap'], function (system, app, viewLocator, bootstrap) {
//>>excludeStart("build", true);
system.debug(true);
//>>excludeEnd("build");
app.title = 'MyApp';
app.configurePlugins({
router: true,
dialog: true,
widget: true
});
app.start().then(function() {
//Replace 'viewmodels' in the moduleId with 'views' to locate the view.
//Look for partial views in a 'views' folder in the root.
viewLocator.useConvention('viewmodels', 'views', 'views');
//Show the app by setting the root view model for our application with a transition.
app.setRoot('viewmodels/shell', 'entrance', 'applicationHost');
});
});
This code works perfectly on all devices except WP8. I tried the line baseUrl: 'x-wmapp0:www/app' to set the actual path used internally by WP8 Cordova, but that does not work. Is that because it is not a path starting with '/' or http?
Any ideas on how to configure requirejs to be able to load modules and views using requirejs?

See if this is any help to you http://mikaelkoskinen.net/durandal-phonegap-windows-phone-8-tutorial/
Also, as of the 18th October 2013, Phonegap Build has added beta support for WP8. Add "winphone: as the gap:platform and ensure you're using phonegap 3.0. We're currently having no luck but maybe you can use that.

I just solve this problem for myself as well, what I ended up doing was waiting for the deviceloaded event before I loaded my main.js.
Cordova applies a patch to XMLHttpRequest which has been applied when deviceloaded has been triggered.
In my app I it ended up looking similar to this:
<script src="js/require.js"></script>
<script>
document.addEventListener('deviceloaded', function() {
var script = document.createElement('script');
script.src = 'js/main.js';
document.body.appendChild(script);
}, false);
</script>
I hope that works out for you as well!
One other thing, I noticed in my app that if I try to load weinre I couldn't get my app started at all with require.js. I haven't been able to research this further yet though.

I recommend to set a breakpoint to cordovalib/XHRHelper.cs HandleCommand method and see what is going on. Also the following version of HandleCommand could work better for you
public bool HandleCommand(string commandStr)
{
if (commandStr.IndexOf("XHRLOCAL") == 0)
{
string url = commandStr.Replace("XHRLOCAL/", "");
Uri uri = new Uri(url, UriKind.RelativeOrAbsolute);
try
{
using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
{
if (isoFile.FileExists(uri.AbsolutePath))
{
using (
TextReader reader =
new StreamReader(isoFile.OpenFile(uri.AbsolutePath, FileMode.Open, FileAccess.Read))
)
{
string text = reader.ReadToEnd();
Browser.InvokeScript("__onXHRLocalCallback", new string[] { "200", text });
return true;
}
}
}
url = uri.AbsolutePath;
}
catch { }
var resource = Application.GetResourceStream(new Uri(url, UriKind.Relative)) ??
// for relative paths and app resources we need to add www folder manually
// there are many related issues on stackoverflow + some prev worked sample don't because of this
Application.GetResourceStream(new Uri("www/" + url, UriKind.Relative));
if (resource == null)
{
// 404 ?
Browser.InvokeScript("__onXHRLocalCallback", new string[] { "404" });
return true;
}
else
{
using (StreamReader streamReader = new StreamReader(resource.Stream))
{
string text = streamReader.ReadToEnd();
Browser.InvokeScript("__onXHRLocalCallback", new string[] { "200", text });
return true;
}
}
}
return false;
}

Related

Qlik Sense mashup RequireJS adding js files gives error 'not a function'

So i never used requireJS before, but because Qlik Sense is using it for its mashups i had to try it one way or another.
I just made a simple bootstrap mashup, added the highcharts library and bought a bootstrap admin theme (name = Naut) on a theme website.
I moved everything i could use from the bought theme to the simple bootstrap mashup (css, html, js) and then i tried to modify the require.config
this is how my require.config file is looking at the moment.
Keep in mind that jQuery is default inside of the requireJS file (i think the developers of Qlik Sense have made it that way by default).
var config = {
host: window.location.hostname,
prefix: "/",
port: window.location.port,
isSecure: window.location.protocol === "https:"
};
require.config( {
baseUrl: ( config.isSecure ? "https://" : "http://" ) + config.host + (config.port ? ":" + config.port: "") + config.prefix + "resources",
paths: {
bootstrap: "/extensions/fitcloud/js/vendor/bootstrap.min",
bootstrapSwitch: "/extensions/fitcloud/js/vendor/bootstrap-switch.min",
highcharts: "/extensions/fitcloud/js/vendor/highcharts",
senseutils: "/extensions/fitcloud/js/vendor/senseUtils",
treefy: "/extensions/fitcloud/js/vendor/bootstrap-treefy.min",
mainsc: "/extensions/fitcloud/js/main",
vendor: "/extensions/fitcloud/scripts/vendor",
plugins: "/extensions/fitcloud/scripts/plugins",
main: "/extensions/fitcloud/scripts/main"
},
shim: {
bootstrap : {
deps : ['jquery']
},
bootstrapSwitch : {
deps : ['jquery']
},
highcharts : {
deps : ['jquery'],
exports: 'Highcharts'
},
treefy : {
deps : ['jquery']
},
mainsc : {
deps : ['treefy']
},
senseutils : {
deps : ['bootstrap']
},
vendor : {
deps : ['jquery']
},
plugins : {
deps : ['vendor']
},
main : {
deps : ['plugins']
}
}
} );
require( ["js/qlik"], function ( qlik ) { qlik.setOnError( function ( error ) { alert( error.message ); } );
require(["jquery", "bootstrap", "bootstrapSwitch", "highcharts", "senseutils", "treefy", "mainsc", "vendor", "plugins", "main"], function (jq, bs, bss, hs, su, tf, ms, ve, pl, ma) {
var app = qlik.openApp('test.qvf', config);
// All the rest of my javascript code goes in here
});
The js files vendor, plugins & main are the javascript files from the theme i bought. When i put them into the require.config and require i start getting errors TypeError: $(...).highcharts is not a function & TypeError: $(...).bootstrapSwitch is not a function and my app is broken, no charts are loaded and bootstrapSwitch buttons are not working eather. If i remove them, everthing is working fine except i don't have the interactivity the theme is having ( closing sidebar, bouncing menu, ... ).
Am i doing anything wrong, or could it be that some function names are used in multiple libraries?
Your start of the extension should look like this (properties, qlik, jquery, always needed the js dependencies after that are optional but you will probably need
define(["./properties", "qlik","jquery","highcharts", "bootstrapSwitch"],
function(Props, qlik,$,highcharts,boostrapswitch) {
To explain, it first loads in the actual files with this part define(["./properties", "qlik","jquery","highcharts", "bootstrapSwitch"],
That is telling Qlik which JS files to bring in (you dont actually need to put.js after the files.
The error you describe happens when you are not properly passing the stuff inside these js files to the function. This is done in the second part..
function(Props, qlik,$,highcharts,boostrapswitch)
You see there are 5 params because you originally pass 5 js files.
You need to make sure they are in the same order for both parts.
Here is an example of a Qlik Sense extension, I recommend you examine the properties.js and the TalkToQlik.js to see how it should look.
https://github.com/cookiejest/TalkToQlik
Here is some instructions for that extension:
http://webofwork.com/qlik-sense-voice-control-extension-for-accessibility/

RequireJS: CDN fallback not working with Kendo

Struggling to set up RequireJS with KendoUI over CDN and can't get fallback to work.
... from amazing burkeholland A Kendo UI ASP.NET MVC SPA Template
This what I begin with :
define([
'../Scripts/kendo/2014.1.416/kendo.router.min',
'../Scripts/kendo/2014.1.416/kendo.view.min',
'../Scripts/kendo/2014.1.416/kendo.fx.min'
], function () {
return kendo;
})
and it works fine.
If kendo.core.min is not defined, first statement in kendo.router says define(["./kendo.core.min"] and it is loaded from proper location.
However, when I try to use CDN with fallback location like this :
requirejs.config({
paths: {
'router': ['//cdn.kendostatic.com/2014.1.416/js/kendo.router.min', '../Scripts/kendo/2014.1.416/kendo.router.min'],
'view': ['//cdn.kendostatic.com/2014.1.416/js/kendo.view.min', '../Scripts/kendo/2014.1.416/kendo.view.min'],
'fx': ['//cdn.kendostatic.com/2014.1.416/js/kendo.fx.min', '../Scripts/kendo/2014.1.416/kendo.fx.min']
}
});
define([
'router',
'view',
'fx'
], function () {
return kendo;
});
requireJS tries to load kendo.core.min from baseUrl location, not fallback location.
Am I missing something?
However, if I try something like this :
requirejs.config({
paths: {
k: ['//cdn.kendostatic.com/2014.1.416/js', '../Scripts/kendo/2014.1.416']
}
});
define([
'k/kendo.router.min',
'k/kendo.view.min',
'k/kendo.fx.min'
], function () {
return kendo;
})
Fallback doesn't work at all... what am I missing?

how to load pagedown editor with requirejs

I am fairly new with requirejs. I have managed to use requirejs with AMD modules such as ace editor etc just fine. I saw on stackoverflow that it is theoretically possible to load normal js with requirejs.
After several attempts, research and some frustrations I have failed to load the pagedown editor with requirejs without errors.
Here is my code:
requirejs.config({
paths: {
jquery: "jquery-2.0.2.min",
bootstrap: "bootstrap.min",
ace: "ace/lib/ace",
prettify: "pagedown/prettify",
pdconv: "pagedown/Markdown.Converter",
pdsanity: "pagedown/Markdown.Sanitizer",
pdeditor: "pagedown/Markdown.Editor",
pdextra: "pagedown/Markdown.Extra",
},
shim: {
"bootstrap": {
deps: ["jquery"]
}
}
});
require(['jquery', 'bootstrap', 'ace/ace', 'prettify', 'pdconv', 'pdeditor', 'pdsanity', 'pdextra'],
function($, Bootstrap, ace, prettyPrint) {
var input = $('#wmd-input').text();
var editor = ace.edit("wmd-input");
var conv = Markdown.getSanitizingConverter();
Markdown.Extra.init(conv, {
extensions: "all",
highlighter: "prettify"
});
var md = new Markdown.Editor(conv);
md.hooks.chain("onPreviewRefresh", prettyPrint); // google code prettify
md.run(editor);
editor.focus();
});
Here is the error I keep getting:
Uncaught TypeError: undefined is not a function Markdown.Editor.js:185
I keep getting that error after each keystroke.
The files are indeed loaded via requirejs but does not work. Is there an easy way to make the pagedown editor work with requirejs or it is not possible.
Any help/advise/suggestions would be greatly appreciated.
Thanks
you can use like this:
requirejs.config({
paths: {
'markdown-converter': "../Scripts/markdown/Markdown.Converter",
'markdown-sanitizer': '../Scripts/markdown/Markdown.Sanitizer'
},
shim: {
"markdown-sanitizer": {
deps: ["markdown-converter"],
exports: "markdown-sanitizer"
}
}
});
// create markdown module
define("markdown",["markdown-converter","markdown-sanitizer"],function(mc, ms) {
return window.Markdown;
});
define("markdown",function(markdown) {
var converter = new Markdown.Converter();
return {
converter:converter
}
});

how can i convert this code using iron-router instead of router

https://github.com/davebryson/meteor_file_upload_example
the above is the original code using Meteor.router
and i wanted to convert this code only using iron-router, instead of previous router package
but the problem is when i upload file,
i can't understand how to convert these code using iron-router api.
i think there's a problem with index.html and serverside main.js code but i can't fix that.
would you please convert this code below using iron router plz?
in serverside main.js in the original code.
Meteor.Router.configure(
{
bodyParser:
{
uploadDir: 'uploads',
hash: 'sha1',
keepExtensions : true
}
}
);
Meteor.Router.add('/upload/file', 'POST',
function()
{
var title = this.request.body.fileTitle,
size = this.request.files.fileInfo.size,
path = this.request.files.fileInfo.path,
name = this.request.files.fileInfo.name,
obj = {title: title, size: size, path: path, name: name};
Files.insert(obj);
// redirect to root
return [301, {Location: '/'}, ""]
}
);
and i'v already converted the code in clientside main.js like below
Router.map(function () {
this.route('listFiles', {path: '/'});
this.route('addFile', {path: '/add'});
});
Template.listFiles.helpers({
list: function () {
return Files.find({});
}
});
Template.listFiles.events({
'click #addFileBtn' : function(e) {
e.preventDefault();
Router.go('/add');
}
});
Template.addFile.events({
'click #cancelBtn': function(e){
e.preventDefault();
Router.go('/');
}
});
Meteor.subscribe("files");
the point is that i can't handle how to use http method in serverside code with iron-router
Meteor now directly allows you to attach middleware to the server using the WebApp package, with standard Connect handlers.
Put webapp inside .meteor/packages of your app. You can then attach middleware to WebApp.connectHandlers inside your app. It's not too well documented yet, but treat it as a normal connect server.

Why does my Handlebars not have a compile method?

I am setting up a Backbone project with Handlebars and I am having an issue with Handlebars not finding the compile method. Here is my config file:
require.config({
hbs: {
templateExtension: '.hbs'
},
paths: {
backbone: "libs/backbone/backbone",
handlebars: 'libs/handlebars/handlebars.amd',
hbs: 'libs/requirejs-hbs/hbs',
jquery: 'libs/jquery/jquery',
jqueryMockAjax: 'libs/jquery-mockjax/jquery.mockjax',
text: 'libs/requirejs-text/text',
templates: 'templates/',
underscore: 'libs/underscore/underscore'
},
shim: {
backbone: {
deps: [
'underscore',
'jquery'
],
exports: 'Backbone'
},
hbs: {
deps: ['handlebars'],
exports: 'hbs'
},
jqueryMockAjax: {
deps: [ 'jquery' ],
exports: '$.mockjax'
},
underscore: {
exports: '_'
}
}
});
require(['app'], function(App) {
'use strict';
var app = new App();
app.render();
});
Here is the app.js that I am trying to render:
define(function(require) {
var Backbone = require('backbone');
var testTemplate = require('hbs!templates/test');
var router = Backbone.View.extend({
el: $('body'),
template: testTemplate,
render: function() {
return $(this.el).html(this.template());
}
});
return router;
});
When Handlebars calls the hbs.js file on line 25 it cannot find the compile function
define(["handlebars"], function(Handlebars) {
var buildMap = {},
templateExtension = ".hbs";
return {
// http://requirejs.org/docs/plugins.html#apiload
load: function (name, parentRequire, onload, config) {
// Get the template extension.
var ext = (config.hbs && config.hbs.templateExtension ? config.hbs.templateExtension : templateExtension);
if (config.isBuild) {
// Use node.js file system module to load the template.
// Sorry, no Rhino support.
var fs = nodeRequire("fs");
var fsPath = config.dirBaseUrl + "/" + name + ext;
buildMap[name] = fs.readFileSync(fsPath).toString();
onload();
} else {
// In browsers use the text-plugin to the load template. This way we
// don't have to deal with ajax stuff
parentRequire(["text!" + name + ext], function(raw) {
// Just return the compiled template
****HERE onload(Handlebars.compile(raw));
});
}
},
// http://requirejs.org/docs/plugins.html#apiwrite
write: function (pluginName, name, write) {
var compiled = Handlebars.precompile(buildMap[name]);
// Write out precompiled version of the template function as AMD
// definition.
write(
"define('hbs!" + name + "', ['handlebars'], function(Handlebars){ \n" +
"return Handlebars.template(" + compiled.toString() + ");\n" +
"});\n"
);
}
};
});
The Handlebars variable gives me the Handlebars environment, but it has an extra layer in it, so I have to change that line to Handlebars.default.compile(raw). Where is that default object coming from and how do I get rid of it? I wouldn't worry about it, but if I pull down this project somewhere else I am always going to have to remember to do that.
I just encountered this myself, using Handlebars for this first time. It's likely that you're using the "runtime" build of Handlebars. I included this one in my requirements, mistakenly assuming it was the minified version or something.
But in fact the runtime version is significantly smaller as it excludes the template compiler, and is for use only with pre-compiled templates. If you're compiling the template client-side then you need the full version from http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v3.0.3.js (Note: This link may be out of date; you're probably better off going directly to handlebarsjs.com and looking for the current download for the "full version", as opposed to runtime.)
Otherwise, you can follow the instructions on the Handlebars website to run the template compiler. You need node for this. The template compiler produces a JavaScript file containing the pre-compiled template code which you need to link to your page along with the Handlebars runtime build.
Here is how I fixed this issue, although I do not understand completely why the configuration above did not work. The hbs plugin had a folder with all the dependencies it needed in it, like handlebars. When I referred to the handlebars copy contained in the hbs directory, then everything worked like it was supposed to. I do not understand why the vanilla copy of handlebars did not work. I was not using the handlebars runtime, it was the full version, but still there was an issue. After I resolved this, then my template stuff just worked.

Categories