JqueryMobile Knockout and Uncaught Error: NOT_FOUND_ERR: DOM Exception 8 - jquery-mobile

I'm trying to use knockout and jquerymobile and can't get it to work.
Here's my code:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<script src="/nw/scripts/jquery-1.8.2.js"></script>
<script src="/nw/scripts/knockout-2.1.0.debug.js"></script>
<script src="/nw/scripts/jquery.mobile-1.2.0.js"></script>
<link rel="stylesheet" href="/nw/scripts/jquery.mobile-1.2.0.css" />
<title>title</title>
</head>
<body>
<div>
<script type="text/javascript">
function AppViewModel() {
this.test = [{ "name": "noam", "age": "36" }, { "name": "yael", "age": "34"}];
}
$(document).ready(function () {
ko.applyBindings(AppViewModel());
});
</script>
<ul data-bind="foreach: test" id="myList">
<li>test <span data-bind="text: name"></span></li>
</ul>
</div>
</body>
</html>
When I run this I get the following error:
Uncaught Error: NOT_FOUND_ERR: DOM Exception 8
When I comment out the jquerymobile scripts, it works.
Any help would be appriciated

The immediate cause of the problem is the placement of the <script> block where ko.applyBindings is called. The example works as-is if you move the <script> block into the <head> tag, as follows: (also note use of pageinit event and data-role="page" attribute)
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
<script src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-2.1.0.debug.js"></script>
<script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
<title>title</title>
<script type="text/javascript">
function AppViewModel() {
this.test = [{ "name": "noam", "age": "36" }, { "name": "yael", "age": "34"}];
}
$(document).bind('pageinit', function () {
ko.applyBindings(AppViewModel());
});
</script>
</head>
<body>
<div data-role="page">
<ul data-bind="foreach: test" id="myList">
<li>test <span data-bind="text: name"></span></li>
</ul>
</div>
</body>
</html>
Keep in mind that both jquery mobile and knockout alter the DOM, and the DOM error is symptomatic of a clash between them, where one library has moved a DOM element that the other one has subsequently tried to address.
To get JQM and knockout to work together (which they do), you need to be quite familiar with when/how JQM makes its changes to the DOM. This page might be a good starting point.

Related

How do I load and run jsPDF from a CDN without receiving an "import declarations" error?

I am wanting to experiment with the jsPDF library but I can't seem to get it to load.
From my Visual Studio MVC _Layout.cshtml page.....
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
</head>
<body>
<main role="main">
#RenderBody()
</main>
#RenderSection("Scripts", required: false)
</body>
</html>
From my Visual Studio MVC pdf.cshtml page...
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<form id="form1">
<div class="btnExport">
<img id="pdfBtn" src="/images/pdf.jpg" style="height: 30px;" />
</div>
</form>
#section Scripts {
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.es.min.js">
</script>
<script type="text/javascript">
const doc = new jsPDF();
$("#pdfBtn").click(function () {
doc.fromHTML($('#form1')[0], 15, 15, {
width: 170
}, function () {
doc.save('sample-file.pdf');
});
</script>
}
I am receiving the following error messages in the browser console...
I've tried several variations/combinations of the variable declaration (as taken from the documentation on the jsPDF GitHub site) but to no avail. Any assistance is greatly appreciated.

jquery ui tooltip items option not working

It seems for some reason the items option here doesn't work. I'm sure I'm doing something wrong but can't get the error. Can you help me?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>test jquery</title>
<link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.min.css" />
<script type="text/javascript" src="jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="jquery-ui-1.10.3.custom.min.js"></script>
<script>
$(document).ready(function() {
$(".div1").tooltip({ items: 'img[alt]'});
});
</script>
</head>
<body>
<div class="div1">
<img src="home-slider-next-button.png" width="26" height="24" alt="test2">
</div>
</body>
</html>
Ok I took a closer look at the tooltip code and see that it seems it doesn't really take the alt attribute for content. It only uses items content as a selector. So my solution, for now, is to use the content option like this:
$(document).ready(function() {
$(".div1").tooltip({ items: 'img[alt]', content:function(){ return $(this).attr('alt'); }});
});
hope it helps others with the same problem.

How to share a ViewModel between different pages in jQuery mobile?

I am trying to share a ViewModel between pages.
Say I have pageA.html and pageB.html and a separate data.js file. pageA has fields bound (using Knockout) and after clicking a button it moves to pageB which also has some fields bound to the same ViewModel. I can't get this to work - what am I missing?
Of course I can keep all pages (data-role="page") inside a single .html file and it would work fine but is that the only way?
EDIT - pageB.html is a copy of pageA - I am trying to show the problem NOT having another login functionality in many pages!!!
This is the code:
pageA.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head lang="en">
<title>PageA</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.3.0/knockout-min.js"></script>
<script src="JS/data.js"></script>
</head>
<body>
<div data-role="page" id="login">
<div id="loginDetails">
<div data-role="fieldcontain">
<label for="username">
Username:</label>
<input type="text" name="name" id="username" data-bind="value: userid" />
</div>
<div data-role="fieldcontain">
<label for="pswd">
Password:</label>
<input type="text" name="name" id="pswd" data-bind="value: pswd" />
</div>
</div>
<a id="btnLogin" data-role="button" data-bind="click: login">Login</a>
</div>
<script type="text/javascript">
ko.applyBindings(S5.myViewModel);
</script>
</body>
</html>
pageB.html (largely the same as above but its javascript block doesn't seem to get called...)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head lang="en">
<title>pageB</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.3.0/knockout-min.js"></script>
<script src="JS/data.js"></script>
</head>
<body>
<div data-role="page" id="abcd">
<div id="loginDetails">
<input type="text" name="name" data-bind="value: userid" />
<input type="text" name="name" data-bind="value: pswd" />
</div>
</div>
<script type="text/javascript">
debugger; <-- THIS NEVER GETS CALLED!!
ko.applyBindings(S5.myViewModel);
</script>
</body>
</html>
data.js
var S5;
(function (S5) {
S5.myViewModel = {
userid: ko.observable('marcel'),
pswd: ko.observable('xxx'),
login: function () {
// ** DO LOGIN CHECK then move to pageB
$.mobile.changePage("pageB.html", { transition: "slideup" });
},
};
})(S5 || (S5 = {}));
jQuery Mobile uses Ajax Navigation to load and change views. When using multi-html page template, it loads first page (html file) entirely. However, for other views /pages fetched with Ajax, it loads contents inside <body> only, neglecting other tags i.e. <script>, <head> etc...
To solve your problem, move any extra JS libraries or code inside <div data-role="page">.

styling dynamic content in jquery mobile

I know there are similar kind of questions asked and answered as well. But my problem is different. Here is code sample that I am using to load and stylize my content.
$("body").on("click","[data-view]",function(){
var view=$(this).attr("data-view");
$("#mainView").load("pageRouter.php?view="+view).trigger("create");
});
I searched forums and found .trigger("create") is the way to stylize the dynamically loaded content.But it is not helping.
Solution
You are doing it incorrectly, load is asynchronous function so you need to wait for it to load the content before you can enhance the content.
You will need to do this:
$("#mainView").load("pageRouter.php?view="+view, function() {
$(this).trigger("create");
});
This will work if you are only loading content but if you are loading a full page, with header and footer then use this:
$("#mainView").load("pageRouter.php?view="+view, function() {
$(this).trigger("pagecreate");
});
Read more about lead and its callback here.
Working example:
index.php
<!DOCTYPE html>
<html>
<head>
<title>jQM Complex Demo</title>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=no; target-densityDpi=device-dpi"/>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>
<script>
$(document).on('pagebeforeshow', '#index', function(){
$("#index").load("load.php", function() {
$(this).trigger("pagecreate");
});
});
</script>
</head>
<body>
<div data-role="page" id="index">
</div>
</body>
</html>
load.php
<div data-theme="b" data-role="header">
<h1>Index page</h1>
</div>
<div data-role="content">
<a data-role="button">Button</a>
</div>

Sammy.js and Knockout.js => Templating without templates?

I am fairly new to the concept of javascript client side development. I am running into an issue, though it may be I just don't understand how to accomplish something with the mash of frameworks.
I know I want to use Knockout for it's rich client side goodies. I also wanna use Sammy.js to allow for routing and passing data to the knockout views (I come from an MVC background where I stuff a model with data, then return view(model), and MVC binds it nice and good for me).
So now I am trying to do something similar client side...
Here is my Index.html :
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title>The EClassifieds Mobile</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<!-- <script type="text/javascript" src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>-->
<script type="text/javascript" charset="utf-8" src="./scripts/cordova-1.8.1.js"></script>
<script type="text/javascript" charset="utf-8" src="./scripts/knockout.js"></script>
<script type="text/javascript" charset="utf-8" src="./scripts/templ.js"></script>
<script type="text/javascript" charset="utf-8" src="./scripts/sammy.js"></script>
<script type="text/javascript" charset="utf-8" src="./scripts/sammy.tmpl.js"></script>
<script type="text/javascript" charset="utf-8" src="./services/RouteManager.js"></script>
<script type="text/javascript" charset="utf-8" src="./services/ApplicationManager.js"></script>
<link rel="stylesheet" href="./style/site.css" type="text/css" media="screen" title="no title" charset="utf-8"/>
<!-- <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />-->
</head>
<body>
<div id="main">
<h1>HELLO WORLD!</h1>
<!--Sammy should update the content of this div dynamically, creating a SPA (single page application)-->
</div>
</body>
</html>
Here is my Sammy Configuration.
(function ($) {
alert('Building Routes');
var app = $.sammy('#main', function () {
this.use('Tmpl', 'html');
this.get('#/', function (context) {
alert('Rendering Partial for Login page');
context.app.swap('Loading...');
this.render("/views/Login.html");
});
});
$(function () {
app.run('#/');
});
})(jQuery);
Here is my Login.html
<!--Model File Goes Here -->
<script type="text/javascript" charset="utf-8" src="../models/Login.js"></script>
<fieldset title="Please Login to Begin :">
<div data-role="content" style="padding: 15px">
<div data-role="fieldcontain">
<fieldset data-role="controlgroup" data-mini="true">
<label for="txtUsername">
Username
</label>
<input id="txtUsername" data-bind="value: username" placeholder="Stevie" value="" type="text" />
</fieldset>
</div>
<div data-role="fieldcontain">
<fieldset data-role="controlgroup" data-mini="true">
<label for="txtPassword">
Password
</label>
<input id="txtPassword" data-bind="value: password" placeholder="yep!" value="" type="password" />
</fieldset>
</div>
<a id="btnLogin" data-role="button" data-transition="fade" href="#page1" >
Login
</a>
</div>
<div id="errorText">
<h1></h1>
</div>
<p id="deviceProperties">Loading device properties...</p>
</fieldset>
<script type="text/javascript">
$(document).ready(function () {
ko.applyBindings(new LoginDataModel(0, "Stevie", "theTV", true));
});
</script>
I also need some way to pass the data from the sammy get handler, to the knockout page. Is there a way to do this, or am I attempting the impossible?
UPDATE 1 :
I would really love to be able to do something like :
var app = $.sammy('#main', function () {
this.use('Tmpl', 'html');
this.get('#/', function (context) {
alert('Rendering Partial for Login page');
context.app.swap('Loading...');
var data = getLoginData();
this.render("/views/Login.html", data);
});
Sammy does this same exact thing using other template frameworks, however, I don't see how I would bind the $data in the Knockout view to the data passed from Sammy.
Not sure if you saw this, but the webmail tutorial on the knockoutjs website uses sammy.js for routing:
http://learn.knockoutjs.com/#/?tutorial=webmail
Here's a link to the finished product (so you can view source if you don't want to follow the whole tutorial)
http://learn.knockoutjs.com/WebmailExampleStandalone.html
the Knockout.js-External-Templates plugin will help you in achieving this behavior. A good starting point will be from here
EDIT: The "starting point" link now goes to malware.
Even John Papa endorses it here
The above solution is useful only when you frequently reuse your templates. Use inline templating whenever possible. Inline templating – and using foreach binding, performs around 1/3 faster than applying template from a separate DOM element, the so-called named template binding. More info on this here

Resources