nb-select on nb-stepper giving error- Form submission canceled because the form is not connected (NgxAdmin) - angular8

I get an error (Form submission canceled because the form is not connected) when moving to the next step in my stepper because of the nb-select. I have a feeling that the nb-option "value" is not properly linking the the formControlName (kinda as the error says). I use FormBuilder and FormGroups. I have read up quite a bit but can't see what might be causing this.
nb-select code
<nb-select formControlName="defaultTechnicianId" *ngIf="technicianList" fullWidth="true"
placeholder="Select a Technician">
<nb-option *ngFor="let technician of technicianList" value="technician.id">
{{technician.firstName}}
</nb-option>
</nb-select>
the form code
<nb-step [stepControl]="createForm" label="Create">
<form [formGroup]="createForm" (ngSubmit)="onCreatePlannedMaintenance()" class="step-container">
<div class="row">
<div class="col-sm-12">
<label for="inputUser" class="label col-sm-12 form-control-label">Default Technician</label>
<nb-select formControlName="defaultTechnicianId" *ngIf="technicianList" fullWidth="true"
placeholder="Select a Technician">
<nb-option *ngFor="let technician of technicianList" value="technician.id">
{{technician.firstName}}
</nb-option>
</nb-select>
</div>
</div>
<button nbButton nbStepperNext>next</button>
</form>
form setup code
this.createForm = this.formBuilder.group({
name: ['', Validators.required],
defaultTechnicianId: ['', Validators.required],
});
Submit code
onCreatePlannedMaintenance() {
this.createForm.markAsDirty();
if (this.createForm.invalid) {
return;
}
this.plannedMaintenance = this.createForm.value;
this.dataService.put(this.plannedMaintenance).subscribe(data => {
this.plannedMaintenance = data;
});
}

I have read that this might be an issue with the older nebular package (I am using 4.1.2). Might not be nebular itself but instead nebular and reactive forms together causing this.
Simple fix is just to add a click event on the Stepper Next Button e.g.
<button nbButton nbStepperNext (click)="onCreatePlannedMaintenance()">next</button>

Related

Assign a value in Vue.js onchange of input

I there guy's im struggling with a form that i need to complete using Vue.JS. Basically i need that the value of the field 'price_vat' its updated with some calculations evry time that input called 'price_user' is updated. Usign jquery evrything is going as well. Butt data is not passed to POST method using Vue.
<div class="col-md-6" v-show="form.active">
<div class="form-group">
<label >{{__('Price')}}</label>
<input type="number" v-model="form.price_user" class="form-control">
</div>
</div>
<div class="col-md-6" v-show="form.active">
<div class="form-group">
<label >{{__('Price with VAT')}}</label>
<input type="number" v-model="form.price_vat" class="form-control">
</div>
</div>
if i understand you correctly,, you want form.price_vat to change, every time you change form.price_user by typing inside the input.
you can do this using watch. just add the below your methods in vue:
watch:{
'form.price_user':function():{
this.form.price_vat += 1
},
}
so in this code, you update the value of form.price_vat by 1 every time the form.price_user changes. you can do anything inside the function of watch.
the complete vue part will be :
data(){
return:{
form:{
price_vat :'',
price_user : '',
}
}
},
methods:{},
watch:{
'form.price_user':function():{
this.form.price_vat += 1
},
}

Not able to click on a button, when isExisting is true; isDisplayedInViewport true, but waitForDisplayed timed out for the element in WebdriverIO

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')

Using vee-validate for validation of dropbox

Sorry for the very basic question
I'm trying to validate a form using vee-validate. text/email/number fields are not a problem. But I couldn't find a good documentation on validating dropdown/checkbox/radio fields.
What I want is "you have to select some option from the dropdown". For that i tried
<p class="help is-danger" v-show="standard===''">Select the standard student is studing in.</p>
where standard is the property which is binded with the help of v-model="standard". This is working as intended, but i want this message to be shown when dropdown is "touched". I'm not able to figure this out.
You can use the data-vv-validate-on attribute:
data-vv-validate-on="focus"
Then whenever the dropdown is opened the validator will fire, for instance.
I found a workaround for this,
<div class="select" :class="{'is-success': standard!='', 'is-danger': standard=='' && standardIsFocused}">
<select v-model="standard" #focus.once="standardToggle()">
...
</select>
</div>
<p class="help has-text-left is-danger" v-show="standard==='' && standardIsFocused">Selecting one of the option is required.</p>
in script tags
data () {
return {
standardIsFocused: false,
},
methods: {
standardToggle() {
this.standardIsFocused = !this.standardIsFocused
}
}

How can I compose a VM into a view within an Aurelia validation renderer

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

Empty TabContainer in Dojo Dialog

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
}