The problem is that the TabConainer inside the Dialog is empty after opening although selected="true" is given (see the screenshot below). The content is called with dojo/html html.set(node, contentHTML, {parseContent: true});
When changing the tab by clicking on another one the content appears and the class "dijitVisible" is set for this div as it should be from the beginning. The attribute nested="true" is necessary since otherwise three select bars are shown over the tabContainer.
What can I do so that the content appears from the start on?
<div data-dojo-type="dijit/Dialog" id="formDialog" data-dojo-id="formDialog" title="Edit member data">
<div id="formContent" class="dijitDialogPaneContentArea" data-dojo-attach-point="formContent">
</div>
</div>
Update:
Here is the whole javascript for getting the content
getForm = function(formID, urlAction){
var contentHTML;
var xhrArgs = {
url: urlAction,
handleAs: "text",
load: function(data){
contentHTML = data;
},
error: function(error){
contentHTML = text_error_unexpected + ": " + error;
},
handle: function(error, ioargs){
var node = dom.byId(formID);
html.set(node, contentHTML, {parseContent: true});
}
}
var deferred = dojo.xhrGet(xhrArgs);
};
Update 2:
This is the content that gets called and inserted in the above div "formContent" (I thought I make the description as simple as possible and lost some details on the way)
<div id="form" data-dojo-type="dijit/form/Form" data-dojo-attach-point="form" encType="multipart/form-data" action="#">
<div style="width: 450px; height: 370px;">
<div data-dojo-type="dijit/layout/TabContainer" nested="true">
<div data-dojo-type="dijit/layout/ContentPane" title="Personal data" selected="true">
Content 1
</div>
<div data-dojo-type="dijit/layout/ContentPane" title="Detailed data">
Content 2
</div>
<div data-dojo-type="dijit/layout/ContentPane" title="Contact data">
Content 3
</div>
</div>
</div>
</div>
Have you tried calling either dialog.resize() or tabcontainer.layout() after adding it to the dialog?
I am not sure as to how the code below will place contents inside the first ContentPane (title="Personal data"). I am assuming that the parameter formID = "form"
html.set(node, contentHTML, {parseContent: true});
I can suggest an alterantive.
Use an id with the content pane as shown below.
<div id="content1" data-dojo-type="dijit/layout/ContentPane" title="Personal data" selected="true">
Content 1
</div>
Then use dijit/registry to get the contentpane widget in the handle function call as shown below.
handle: function(error, ioargs){
var content= registry.bId(formId); // over here formId = "content1"
content.set("content","<p>This is content for <b>Personal Data</b></p>");
//content.set("content", contentHTML);
}
EDIT 1
This is may be one possible solution.
#Richard had suggested dialog.resize(), which I did try to put it after the html.set code but it would not work.
What I have noticed is that the html.set takes some time to execute and the dialog.resize() does not work because it is
called before the completion of the html.set call.
html.set also complicates the issue as it does not provide any handle (promise object) to let us know when it has finished execution.
so the below solution uses a setTimeout call to delay the execution of the dialog.resize(). Hence would advice to put the value of delay time depending upon some actual UI testing.
Modified code.
handle: function(error, ioargs){
var node = dom.byId(formID);
html.set(node, contentHTML, {parseContent: true});
var dialog = registry.bId("formDialog");
setTimeout( function(){
dialog.show();
dialog.resize();
},2000) // time delay of 2 seconds
}
Related
The script fails with this error.
Error: element (".WONDERESC") still not displayed after 30000ms
Tried different combinations for Xpath, (relative, fixed, text()} and CSS selectors, but the button not clicked. The sign-in button div in the code block:
<div>
<div class="WONDERBSC" role="form">
<div>
<div class="WONDERJ1B" data-automation-id="userName">
<div class="TOM-Label WONDERP1B"
title="Username">Username</div>
<input type="text"
class="TOM-TextBox WONDERM1B" aria-label="Username">
<button type="button" class="TOM-Button WONDERN1B"/>
</div>
</div>
<div>
<div class="WONDERJ1B"
data-automation-id="password">
<div class="TOM-Label WONDERP1B" title="Password">Password</div>
<input type="password" class="TOM-PasswordTextBox WONDERM1B" aria-label="Password">
<button type="button" class="TOM-Button WONDERN1B"/>
</div>
</div>
<button type="button"
class="WONDERESC"
data-automation-id="goButton">Sign In</button>
</div>
</div>
Kindly suggest the workarounds - the other conditions are also meeting- visibility-true, display-block, opacity not zero.
Thanks,
Tan
If element is not displayed then you have to make it visible
Case 1
The element takes some time to be visible automatically
In this case, you can use webdriver wait
WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(10));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("xxxx"));
Case 2
Element is visible after some interaction like mouse movement or click or type
Then you have to perform that action with selenium. For mouse movements you can use action classes
As it was told in the comments, you are using invalid selectors.
Assuming you have the latest WebdriverIO v6, the following works like a charm
// open page
browser.url('https://impl.workday.com/wday/authgwy/accenture_dpt2/login.htmld?redirect=n')
const form = $('[data-automation-id="authPanel"] [role="form"]')
// make sure form is visible
expect(form).toBeVisible()
// define form data
const formData = [{
id: 'userName', value: 'test'
}, {
id: 'password', value: 'password'
}]
// fill form
formData.forEach(f => {
form.$(`[data-automation-id="${f.id}"] input`).setValue(f.value)
})
// submit form
form.$('button[data-automation-id="goButton"]').click()
// make sure error message exist
const errorMessage = $('[data-automation-id="alertMessage"]')
expect(errorMessage).toBeVisible()
expect(errorMessage).toHaveTextContaining('Invalid user name or password')
I'm trying to use the aurelia-validation plugin to perform validation on a form. I'm creating a custom validation renderer that will change the color of the input box as well as place an icon next to the box. When the icon is clicked or hovered, a popup message appears that will display the actual error message.
Currently, I'm rendering all of this in code manually in the renderer, but it seems like it would be nice to have the html for all of this defined in an html file along with the associated js file to handle the click and hover on the icon. IOW, encapsulate all the error stuff (icon with popup) in a View/ViewModel and then in the render() of my validation renderer, somehow just compose a new instance of this just after the element in question.
Is this possible to do? I've seen how to use <compose></compose> element but I really am trying to avoid having to add that to all of my forms' input boxes.
This is what I currently have in my renderer:
import {ValidationError, RenderInstruction} from 'aurelia-validation'
export class IconValidationRenderer {
render(instruction){
//Unrender old errors
for(let {result, elements} of instruction.unrender){
for(let element of elements){
this.remove(element, result);
}
}
//Render new errors
for(let {result, elements} of instruction.render){
for(let element of elements){
this.add(element, result)
}
}
}
add(element, result){
if(result.valid)
return
//See if error element already exists
if(element.className.indexOf("has-error") < 0){
let errorIcon = document.createElement("i")
errorIcon.className = "fa fa-exclamation-circle"
errorIcon.style.color = "darkred"
errorIcon.style.paddingLeft = "5px"
errorIcon.id = `error-icon-${result.id}`
errorIcon.click = ""
element.parentNode.appendChild(errorIcon)
element.classList.add("has-error")
element.parentNode.style.alignItems = "center"
let errorpop = document.createElement("div")
let errorarrow = document.createElement("div")
let errorbody = document.createElement("div")
errorpop.id = `error-pop-${result.id}`
errorpop.className = "flex-row errorpop"
errorarrow.className = "poparrow"
errorbody.className = "flex-col popmessages"
errorbody.innerText = result.message
console.log("Computing position")
let elemRec = errorIcon.getBoundingClientRect()
let elemH = errorIcon.clientHeight
errorpop.style.top = elemRec.top - 10 + "px"
errorpop.style.left = elemRec.right + "px"
errorpop.appendChild(errorarrow)
errorpop.appendChild(errorbody)
element.parentNode.appendChild(errorpop)
}
}
remove(element, result){
if(result.valid)
return
element.classList.remove("has-error")
let errorIcon = element.parentNode
.querySelector(`#error-icon-${result.id}`)
if(errorIcon)
element.parentNode.removeChild(errorIcon)
//Need to remove validation popup element
}
}
Thanks for any help you can offer.
P.S. At this point, I am not implementing a click or hover like I mentioned -- that is something that I would like to do but I'm not even sure how at this point. Would be more straight forward if I can compose a VM.
EDIT
I was pointed to this article by someone on the Aurelia Gitter channel. I've tried implementing the TemplatingEngine but clearly I'm not going about it the right way. Here's what I have.
add-person-dialog.js //VM that has form with validation
import {TemplatingEngine,NewInstance} from 'aurelia-framework'
import {ValidationController} from 'aurelia-validation'
import {IconValidationRenderer} from './resources/validation/icon-validation-renderer'
export class AddPersonDialog {
static inject = [NewInstance.of(ValidationController),TemplatingEngine]
constructor(vc, te){
this.vc = vc
this.vc.addRenderer(new IconValidationRenderer(te))
}
icon-validation-renderer.js
//Plus all the other bits that I posted in the code above
constructor(te){
this.te = te
}
add(element, result){
if(result.valid) return
if(element.className.indexOf("has-error") < 0 {
//replaced there error icon code above with this (as well as a few different variations
let test = document.createElement("field-error-info")
element.parentNode.appendChild(test)
this.te.enhance({element: test})
}
}
field-error-info.html
<template>
<require from="./field-error-info.css" ></require>
<i class="fa fa-exclamation-circle" click.delegate="displayMessage = !displayMessage" mouseenter.delegate="displayMessage = true" mouseleave.delegate="displayMessage = false"></i>
<div show.bind="displayMessage" class="flex-row errorpop" style="left:300px">
<div class="poparrow"></div>
<div class="flexcol popmessages">Message 1</div>
</div>
</template>
Ultimately, <field-error-info></field-error-info> gets added to the DOM but doesn't actually get rendered. (Incidentally, I also tried adding <require from='./elements/field-error-info'></require> in the add-person-dialog.html.
You could create a form control custom element that encapsulates the error icon and tooltip logic. The element could expose two content projection slots to enable passing in a label and input/select/etc:
<template>
<div validation-errors.bind="errors"
class="form-group ${errors.length ? 'has-error' : ''}">
<!-- label slot -->
<slot name="label"></slot>
<!-- input slot -->
<slot name="input"></slot>
<!-- icon/tooltip stuff -->
<span class="control-label glyphicon glyphicon-exclamation-sign tooltips"
show.bind="errors.length">
<span>
<span repeat.for="errorInfo of errors">${errorInfo.error.message}</span>
</span>
</span>
</div>
</template>
Here's how it would be used:
<template>
<require from="./form-control.html"></require>
<form novalidate autofill="off">
<form-control>
<label slot="label" for="firstName" class="control-label">First Name:</label>
<input slot="input" type="text" class="form-control"
value.bind="firstName & validateOnChange">
</form-control>
<form-control>
<label slot="label" for="lastName" class="control-label">Last Name:</label>
<input slot="input" type="text" class="form-control"
value.bind="lastName & validateOnChange">
</form-control>
</form>
</template>
Live example: https://gist.run/?id=874b100da054559929d5761bdeeb651c
please excuse the crappy tooltip css
I have a problem with this jQuery function that i use for add and remove box to my page:
jQuery(document).ready(function($){
$('.my2-form .add2-box').click(function(){
var n = $('.text2-box').length + 1;
if( 12 < n ) {
alert('you can't make more than 12 box');
return false;
}
$.post('showselectdatearray.php', { type: 'months', year: 93}, function(result) {
var box_html = $('<p class="text2-box" style="padding: 0px; margin: 0px;"><label for="box' + n + '"><span class="box2-number">' + n + ' </span></label> <input type="text" name="boxes[]" value="" id="box' + n + '" size="8" /> '+resultremoveitem</p>');
box_html.hide();
$('.my2-form p.text2-box:last').after(box_html);
box_html.fadeIn('slow');
box_html.css( 'background-color', '#48b973' );
return false; });
});
$('.my2-form').on('click', '.remove2-box', function(){
$(this).parent().css( 'background-color', '#FF6C6C' );
$(this).parent().fadeOut("slow", function() {
$(this).remove();
$('.box2-number').each(function(index){
var p =index+1;
var str = p+'\xa0\xa0\xa0\xa0';
$(this).text( str );
});
});
return false;
});
$('.my2-form p.text2-box:last').css( 'background-color', '#FFFFFF' );
});
then i use from above script in my code this way:
<div id="showresult12" class="my2-form">
<div>
<input type='button' id='AddMore' name='AddMore' value='add box' class='add2-box' />
</div>
<div style="float: right;" class="scroll10">
<p class="text2-box" style="padding: 0px; margin: 0px;">
<label for="box"><span class="box2-number">1 </span></label>
<input type="text" name="boxes[]" value="" id="box" size="8" />
<?php Show_Select_Date_Array("months",0,0,0,93) ?>
</p>
</div>
</div>
Every thing is OK now and when user click on "add box" button, another box appear and when user click on "remove it" button, one box remove.
I have another part -part2- under this code that fetch from database. after user click on "edit" button that is locate in -part2-, information fetch from database to boxes with php code, but my add and remove button don't work at all. my information fetch with Ajax and replace in new boxes. the 'showresult12' div id completely load again with same data.
what is the problem after replacing div element?!
and what change i must do in my jquery code that it work after div load again?
In your 'var box_html=...' line, there looks to me to be a bit of a syntax error:
'+resultremoveitem</p>');
where 'result' isn't used properly. Should it be something like +result+'<a href... ?
EDIT: If as you say your 'showresult12' div is being emptied and then refilled again dynamically, then your 'add' event handler will always be invalid - it's not using delegation like the 'remove' one.
$('.my2-form').on('click', '.remove2-box', function(){ - this is OK, as it will work for dynamically-created .remove2-box elements.
$('.my2-form .add2-box').click(function(){... - however this is not, as it is only valid for .add2-box elements that were present in the DOM when this handler was created.
So in this scenario, the 'add' hander will not work following your AJAX PHP call.
Furthermore, if you are actually going further and removing and re-adding the .my2-form div (#showresult12) itself, then neither of the handlers will work - you would have to do something like $('body').on('click', '.my2-form .add2-box', function() {....
thanks for your answer but my result fetch from file with name "showselectdatearray.php". it is not important you can remove this
$.post('showselectdatearray.php', { type: 'months', year: 93}, function(result) {
AND result variable in : '+result<a href="#"
I have created a widget based template like,
<div class="content">
<div>
<!-- rest of content-->
</div>
<div class="col-md-6">
<div class="panel" data-dojo-attach-point="sysinfo">
<ul class="col-md-12 stats">
<li class="stat col-md-3 col-sm-3 col-xs-6">Host:</br> <span><b class="value">{{hname}}</b></span>
</li>
<li class="stat col-md-3 col-sm-3 col-xs-6"># CPU:</br> <span><b class="value">{{cpu}}</b></span>
</li>
</ul>
</div>
</div>
</div>
How do I update only content of sysinfo ?
Till now I was doing,
var widget = this;
widget.template = new dtl.Template(widget.templateString);
var template = widget.template;
template.update(node, stats); // but it update complete content as node == content. I just want to refresh sysinfo.
I also tried,
template.update(this.sysinfo, stats); // but it throws exceptions
Any ideas?
As far as I can see is that when you're using dojox/dtl/_Templated as suggested in the documentation, there is no update() function available.
If you really wish for certain things, you will have to manually define a template and render that one (and replace the attach point), for example:
var subtemplate = "<ul data-dojo-attach-point='sysinfo'>{% for item in list %}<li>{{item}}</li>{% endfor %}</ul>";
var template = "<div><h1>{{title}}</h1>" + subtemplate + "</div>";
var CustomList = declare("custom/List", [ _WidgetBase, _Templated, _DomTemplated ], {
templateString: template,
subTemplate: new dtl.Template(subtemplate),
title: "Fruits",
list: [ 'Apple', 'Banana', 'Lemon' ],
_setListAttr: function(list) {
this.list = list;
this.sysinfo = domConstruct.place(this.subTemplate.render(new dtl.Context(this)), this.sysinfo, "replace");
},
_getListAttr: function(list) {
return this.list;
}
});
Normally, if you would update the template when the list is set, you could use this.render() inside the _setListAttr() function to update the entire template.
However, as you can see in the _setListAttr() function I'm replacing an attach point by a newly rendered Django template.
This results in only that part of the template being updated, in stead of the entire template. So {{title}} would remain the original value, even when changed.
A full example can be found on JSFiddle: http://jsfiddle.net/pb3k3/
Idea:
After dynamic content is loaded, on mouseover I'm trying to render google share button like it says on the official google developer's site.
Code I'm using is:
gapi.plus.render(div);
Facts:
If I change plus to plusone, it renders google plus button instead share. ( Means: Scripts load up )
If I remove {"parsetags": "explicit"}, Buttons load up ( But doesn't load up on hover )
Problem:
Share button doesn't load up.
Debuging links with plus.render and plusone.render:
http://romanlosev.igloro.info/googleshare.php?load=plusone ( plusone - works, but plus+ buttons load up )
http://romanlosev.igloro.info/googleshare.php?load=plus ( plus - doesn't works )
There's a similar question on StackOverflow here.
What you need to do is call the explicit render method for the share buttons. Replacing your function that selects the div with the following code will delay render for the share objects on screen.
$("#clickme").click(function()
{
gapi.plus.go();
});
To render individual buttons, you must pass an object with the action parameter set to share, for example:
gapi.plus.render("plusOne", {action: "share"});
The following is a more complete example, that does asynchronous script loading and renders various share targets, visible here:
<html>
<body>
<p>
<div data-action="share" class="g-plus" id="plusOne"></div>
<button onClick="gapi.plus.render('plusOne', getParamBag('https://www.google.com'))"></button>
</p>
<p>
<div data-action="share" class="g-plus" id="plusTwo"></div>
<button onClick="gapi.plus.render('plusTwo', getParamBag('https://plus.google.com'))"> </button>
</p>
<p>
<div data-action="share" class="g-plus" id="plusThree"></div>
<button onClick="gapi.plus.render('plusThree', getParamBag('https://developers.google.com'))"></button>
</p>
</body>
<script type="text/javascript">
window.___gcfg = {
lang: 'en-US',
parsetags: 'explicit'
};
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
function getParamBag(url){
return {
action: "share",
href: url
};
}
</script>
</html>