I am using the DurandalJS framework for my PHP web application. I am exploiting DurandalJS framework features for showing modal views.
I have a homepage, home.html which contains a link to a page called, autocomplete.html. When this link is clicked, it opens the autocomplete.html page inside a modal view (a feature provided by DurandalJS).
I am also using the jQuery-UI autocomplete feature to create an autocomplete for a textbox. When a user types anything into the textbox, he gets a list of suggestions based on the characters he enters through the keyboard.
The problem here is that the autocomplete feature works if the autocomplete.html page is run independently in the browser. However, this feature doesn't run when the page is shown in the modal i.e. by running (navigating) the project through the DurandalJS framework.
Can anyone please tell me where exactly am I going wrong? Replies at the earliest will be highly appreciated.
The source code for my project is given below. Please note that the order in which I have provided the source code is in the same order in which the DurandalJS navigation call stack is executed. The flow of my application is, index.php >>> main.js >>> shell.js >>> shell.html >>> home.js >>> home.html >>> autocomplete.js >>> autocomplete.html.
The autocomplete.js >>> autocomplete.html call stack is executed when the user clicks on the Go to Autocomplete link on the home.html page.
main.js
require.config({
paths: {
'text': 'durandal/amd/text'
}
});
define(function (require) {
var app = require('durandal/app'),
viewLocator = require('durandal/viewLocator'),
system = require('durandal/system'),
router = require('durandal/plugins/router');
//>>excludeStart("build", true);
system.debug(true);
//>>excludeEnd("build");
app.start().then(function () {
//The following statement is to help DurandalJS to find files only according to their names.
//Replace 'viewmodels' in the moduleId with 'views' to locate the view.
//Look for partial views in a 'views' folder in the root.
viewLocator.useConvention();
//configure routing
router.useConvention();
router.mapNav("pages/home");
router.mapNav("pages/autocomplete");
app.adaptToDevice();
//Show the app by setting the root view model for our application with a transition.
app.setRoot('viewmodels/shell', 'entrance');
});
});
shell.js
define(function (require) {
var router = require('durandal/plugins/router');
return {
router: router,
activate: function () {
return router.activate('pages/home');
}
};
});
shell.html
<br />
<br />
<br />
<br />
<div class="container-fluid page-host">
<!--ko compose: {
model: router.activeItem, //wiring the router
afterCompose: router.afterCompose, //wiring the router
transition:'entrance', //use the 'entrance' transition when switching views
cacheViews:true //telling composition to keep views in the dom, and reuse them (only a good idea with singleton view models)
}--><!--/ko-->
</div>
home.js
// JavaScript Document
//This file loads the respective page's ViewModel (<Page>.js) and displays the View (<page>.html)
define(function (require) {
self.app = require('durandal/app');
return {
movies: ko.observable(),
activate: function() {
var self = this;
//The following code in the function creates a modal view for the autocomplete page
self.viewAutoCompleteModal = function(AutoComplete, element) {
app.showModal("viewmodels/pages/autocomplete");
};
}
};
});
home.html
<div id="applicationHost">
<div class="navbar navbar-fixed-top navbar-inverse">
<div class="navbar-inner">
<div class="container">
<a class="brand">
<span>My application</span>
</a>
</div>
</div>
</div>
</div>
<!--The following lines of code create href links for the My Application pages and directs the DurandalJS to the respective pages. The data-bind attribute calls the view<Page>Modal functions (which create a Modal view) which is defined in the ViewModel (<Page>.js file)-->
<br />
<br />
Go to Autocomplete
autocomplete.js
// JavaScript Document
define(function (require) {
var router = require('durandal/plugins/router');
var moviesRepository = require("repositories/moviesRepository");
return {
activate: function (context) {
}
};
});
autocomplete.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<title>jQuery-UI Autocomplete Demo</title>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
<script src="http://localhost/rockontechnologies/Scripts/Script1.10.3/jquery-1.9.1.js"></script>
<script src="http://localhost/rockontechnologies/Scripts/Script1.10.3/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css">
<script>
$(function() {
var availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C",
"C++",
"Clojure",
"COBOL",
"ColdFusion",
"Erlang",
"Fortran",
"Groovy",
"Haskell",
"Java",
"JavaScript",
"Lisp",
"Perl",
"PHP",
"Python",
"Ruby",
"Scala",
"Scheme"
];
$( "#tags" ).autocomplete({
source: availableTags
});
});
</script>
</head>
<body>
<div class="modal-footer">
<ul class="btn-group">
<button class="btn" data-bind="click: closeModal">Exit</button>
</ul>
</div>
<div class="ui-widget">
<label for="tags">Tags: </label>
<input id="tags">
</div>
</body>
</html>
For help on DurandalJS, I have referred to:
http://durandaljs.com/
For help on Autocomplete, I have referred to: [http://jqueryui.com/autocomplete/][3]
Thank you in advance.
ive answered a similar question here which will help you.
But your autocomplete.html is wrong and will not work when composed by Durandal. You need to convert that to a durandal style html page.
Add your script tags to your host page. In Hot Towel this is managed by bundles so im not entirely sure where you add these if using PHP.
Remove the HTML, SCRIPT, META etc... Just leave the pure HTML markup.
e.g:
<div class="ui-widget">
<label for="tags">Tags: </label>
<input id="tags">
</div>
Then in your autocomplete.js file, add an attached method or if using Durandal < 2.0.0 you add a viewAttached method.
define(function (require) {
var router = require('durandal/plugins/router');
var moviesRepository = require("repositories/moviesRepository");
return {
activate: function (context) {
},
attached: function (view) {
var $tagInput = $(view).find('#tags');
var availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C",
"C++",
"Clojure",
"COBOL",
"ColdFusion",
"Erlang",
"Fortran",
"Groovy",
"Haskell",
"Java",
"JavaScript",
"Lisp",
"Perl",
"PHP",
"Python",
"Ruby",
"Scala",
"Scheme"
];
$tagInput.autocomplete({
source: availableTags
});
}
};
});
Let me know if you are still having issues and ill be pleased to help.
Related
This code for after login user should post some hello message.
describe("launching Telekha",function(){
it("navigating to signin page",function(){
browser.get("www");
element(by.model("credentials.email")).sendKeys("abnsd6#gmail.com");
element(by.model("credentials.password")).sendKeys("123456");
var ptr = element( by.css('[ng-click="login()"]') );
ptr.click();
});
it("on dashboard",function(){
element(by.model("post.postText")).sendKeys("hello");
element( by.css('[ng-click="postit()"]') ).click();
});
});
HTML code for the button
<textarea id="post-editor" placeholder="Tell your friends" ng-model="post.postText" class="textareanoborder col-xs-12 col-md-12 ng-pristine ng-valid ng-isolate-scope ng-touched" autocomplete="off" aria-invalid="false"> </textarea>
This is a guess, but from experience it usually isn't far off. When the page you are navigating to is loaded, are there any animations, AJAX requests or other delays, separate from AngularJS that might be occurring? Protractor does not wait for these and will execute the code:
element(by.model("post.postText")).sendKeys("hello");
as soon as it can. If when this is executed, all the animations have not yet been completed, you element will not be visible to protractor and you'll see the error you've encountered.
To quickly test this, add a browser.sleep(10000); before the line where it's failing. browser.sleep(); is a command that will force the browser to wait for a set amount of time, in this case 10.000 milliseconds (10 seconds).
If this does end up working, you might want to change it to something more elegant such as:
browser.wait(function() {
return element(by.model("post.postText")).isPresent();
}, 10000);
Which will wait for your element to become visible, but only for a maximum of 10 seconds, after which it will continue anyway.
EDIT1: (which works fine):
HTML (Serving from http://localhost:8080)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Example</title>
<script src="bower_components/angular/angular.min.js"></script>
<script>
var app = angular.module('app', []);
app.controller('myCtrl', function($scope) {
});
</script>
</head>
<body ng-app="app" ng-controller="myCtrl">
<textarea id="post-editor" placeholder="Tell your friends" ng-model="post.postText" class="textareanoborder col-xs-12 col-md-12 ng-pristine ng-valid ng-isolate-scope ng-touched" autocomplete="off" aria-invalid="false"> </textarea>
</body>
</html>
spec.js
describe('angularjs homepage todo list', function() {
it('should add a todo', function() {
browser.get('http://localhost:8080');
$("#post-editor").sendKeys("testlol");
browser.sleep(2000);
});
});
conf.js
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['spec.js']
};
You can implement protractor.ExpectedConditions.visibilityOf() method to wait until element is visible on UI and then send data to input field.
var EC=protractor.ExpectedConditions;
it("on dashboard",function(){
var ele=element(by.id("post-editor"));
browser.wait(EC.visibilityOf(ele),8000,'Ele is not presented');
ele.sendKeys("hello");
element( by.css('[ng-click="postit()"]') ).click();
});
I am trying to develop custom modal plugin for durandal 2.1 to have my own logic and abstract it from the rest of my app here is what I have so far but something does not work and modal gets inserted in DOM twice
define(['jquery', 'knockout', 'plugins/dialog'], function ($, ko, dialog) {
var modal = {
install: function (config) {
dialog.addContext("Modal", {
addHost: function (theDialog) {
var body = $("body");
$('<div id="Dialog" class="AlignC"><div class="ModalHost"></div></div>').appendTo(body);
theDialog.host = $('#Dialog').get(0);
},
removeHost: function (theDialog) {
alert("demoving host");
$("#Dialog").remove();
},
compositionComplete: function (child, parent, context) {
var theDialog = dialog.getDialog(context.model);
}
});
}
};
return modal;
});
and here is how i call it from my viewmodel
dialog.show(this, null, 'Modal');
can anyone tell me what is wrang with this code why my model ELEMENT is inserted twice and ovelay each other. how can i fix that.
second element does not have content inside.
by the way here is view I am trying to show inside modal
<span class="Loader"></span>
<div class="Modal">
<h2 class="Caps">SomeName</h2>
<div class="Row">
<input type="text" />
</div>
<div class="Desc">
description
<br />
XXY YYX XXY
</div>
<div class="Buttons">
<span class="Green">Check</span>
<span>Add</span>
</div>
</div>
Ok I managed to fix this behavior. the problem with click binding was firing twice and this was the problem associated with inserting tow HTML elements in DOM after fixing click handler, everything works just fine.
I have two forms on a page containing Google captcha code, but only one code works. Does anyone know if you can use the same code with the same key on two forms on the same page?,
Thks,
Yes, you can. But you have to explicitly render the widget as mentioned on the developer guide
you should use something like this on your front end(taken from the developer guide):
<html>
<head>
<title>reCAPTCHA demo: Explicit render for multiple widgets</title>
<script type="text/javascript">
var verifyCallback = function(response) {
alert(response);
};
var widgetId1;
var widgetId2;
var onloadCallback = function() {
// Renders the HTML element with id 'example1' as a reCAPTCHA widget.
// The id of the reCAPTCHA widget is assigned to 'widgetId1'.
widgetId1 = grecaptcha.render('example1', {
'sitekey' : 'your_site_key',
'theme' : 'light'
});
widgetId2 = grecaptcha.render(document.getElementById('example2'), {
'sitekey' : 'your_site_key'
});
grecaptcha.render('example3', {
'sitekey' : 'your_site_key',
'callback' : verifyCallback,
'theme' : 'dark'
});
};
</script>
</head>
<body>
<!-- The g-recaptcha-response string displays in an alert message upon submit. -->
<form action="javascript:alert(grecaptcha.getResponse(widgetId1));">
<div id="example1"></div>
<br>
<input type="submit" value="getResponse">
</form>
<br>
<!-- Resets reCAPTCHA widgetId2 upon submit. -->
<form action="javascript:grecaptcha.reset(widgetId2);">
<div id="example2"></div>
<br>
<input type="submit" value="reset">
</form>
<br>
<!-- POSTs back to the page's URL upon submit with a g-recaptcha-response POST parameter. -->
<form action="?" method="POST">
<div id="example3"></div>
<br>
<input type="submit" value="Submit">
</form>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"
async defer>
</script>
</body>
</html>
I just wanted a HTML snipped which I can insert multiple times, each time displaying another captcha. Also, I did not want to take care for specific IDs assigned to the containers, which would be very annoying when multiple formulars still appearing on one page will be designed and rendered independently. Here is my solution.
<div class="g-recaptcha"></div>
<script type="text/javascript"><![CDATA[
function renderCaptchas() {
var captchaNodes = document.getElementsByClassName('g-recaptcha');
for (var i = 0; i < captchaNodes.length; i++) {
var captchaNode = captchaNodes[i];
if (!captchaNode.captchaRendered) {
captchaNode.captchaRendered = true;
grecaptcha.render(captchaNode, {"sitekey": "YOUR_SITE_KEY"});
}
}
}
]]></script>
<script src="https://www.google.com/recaptcha/api.js?onload=renderCaptchas&render=explicit" async="async" defer="defer"></script>
In my JQUerymobile pages, I have embedded popup div.
Here is an example of my pages content :
<html>
<head>...</head>
<body>
<div data-role="page" id="myPage" data-dom-cache="true" data-theme="a">
<div data-role="content" data-theme="a" >...</div>
<div data-role="footer" data-theme="a" data-id="footer-sante" data-position="fixed">...</div>
<div data-role="popup" id="popupOne" data-dom-cache="true" data-theme="b">
</div>
</div>
<div data-role="popup" id="popupTwo" data-dom-cache="true" data-theme="b">
...
</div>
</body>
</html>
I navigate from pages to anothers. Suddently, my embedded popups disappear from my DOM when I inspect my code.
As shown in my example, the popup location in the source code doesn't seem to change anything to the problem.
Since popups are removed from DOM, the code bellow does nothing (it actually worked before) :
$('#popupOne').trigger('create');
$('#popupOne').popup({ transition: "slidedown", position:"position-header" });
$('#popupOne').popup('open');
Is there a solution to keep my popups in my DOM ?
Is there a better location to embed popups in source code ?
Another way could be to load a popup from an external (cached) page but i never achieved to do that by javascript.
Any idea to solve the problem (or a workaround) ?
(Both) your HTML placements might be incorrect here. Remove the popupOne markup from the end of the page and paste it inside the div with data-role=content like this :
<div data-role="page" id="myPage" data-dom-cache="true" data-theme="a">
<div data-role="content" data-theme="a" >
<div data-role="popup" id="popupOne" data-dom-cache="true" data-theme="b"></div>
</div>
<div data-role="footer" data-theme="a" data-id="footer-sante" data-position="fixed">...</div>
</div>
And if you want to reuse popups, I suggest you go the JS way. You could create popups n the fly and open them. Here's some code which does just that. Feel free to alter it to any thing you want :)
$.extend({
"makePopup": function (text) {
var $popup;
//creat popup element
$popup = $("<div/>", {
"data-role": "popup",
"data-theme": "a",
"data-overlay-theme": "a",
"data-transition": "pop"
}).popup();
//create close element
var $close = $("<a/>", {
"data-role": "button",
"html": "Close",
"href": "#",
"data-theme": "e"
}).on("click", function () {
//click event of close element
$(this).closest("[data-role=popup]").popup("close");
}).buttonMarkup();
//create content div - makes a nice jQM page structure.
var $content = $("<div/>", {
"data-role": "content",
//change this any way you want- Im just adding the text from clicked link here.
"html": "<span>" + text + "</span>"
});
//append $close to $content, then append $content to $popup
$content.append($close).appendTo($popup);
return $popup;
}
});
And when you want to use this, just do this,
var popupEl = $.makePopup("Some HTML");
And then you could, say, open it :
popupEl.popup("open");
Or simply,
$.makePopup("Some HTML").popup("open");
Here's a demo : http://jsfiddle.net/hungerpain/xjz3V/
Hope this is what you wanted :)
I'm trying to create a Dojo dialog in Zend Framework but I've run into some problems. My view code looks something like this:
<script type="text/javascript" src="<?= $this->baseUrl('/js/dojo-release-1.7.2/dojo/dojo.js')?>"
data-dojo-config="async: true" dojoConfig = "parseOnLoad: true">
</script>
<script>
require(["dijit/registry", "dojo/ready", "dojo/dom", "dijit/Dialog", "dijit/form/Form"],
function(registry, ready, dom, Dialog){
ready(function() {
createDialog = function(titleText, contentText) {
var node = dojo.byId("foobar");
var myDialog = new Dialog({ title:"From Source Node" }, node);
myDialog.show();
};
});
});
</script>
<body class="claro">
<div data-dojo-type="dijit/Dialog" id="foobar" title="Foo!" style="display: none">
<p>I am some content</p>
</div>
</body>
The button code that loads the dialog looks as follows:
<button name="btnDialog" id="dialogbtn" type="button" onclick='createDialog();'>Open</button>
The first time the button is clicked the dialog opens as expected, but once the dialog is closed and the button is clicked again, the dialog doesn't open and I get the following error in the console.
Tried to register widget with id==foobar but that id is already registered.
What am I doing wrong?
Thanks
Figured it out. I think the form wasn't parsing correctly because the dojo-config was incorrect. Changed the javascript code as follows:
<script type="text/javascript" src="<?= $this->baseUrl('/js/dojo-release-1.7.2/dojo/dojo.js')?>"
data-dojo-config="async: true, parseOnLoad:true">
</script>
<script>
require(["dijit/registry", "dijit/Dialog"], function (registry)
{
createDialog = function createDialog()
{
registry.byId("foobar").show();
}
});
</script>
and the div as follows:
<body class="claro">
<div class="dijitHidden">
<div data-dojo-type="dijit.Dialog" data-dojo-props="title:'Foo!'" id="foobar">
<p>I am some content</p>
</div>
</div>
</body>
and now the dialog dijit is saved to the registry and it's working as expected