I'm try to create test for my Bootstrap project. I'm use Coypu. But I ran into a some problem. I can't check my check-boxes. The problem is that I changed style form my check-box. And now standard Bootstraps check-boxes is hidden. The new check-box is hidden inside standard pattern:
<label>
<input type="checkbox" data-bind="checkedValue: key, checked: $parent.selectedCatchments, attr: { id: key }" class="catchment-checkbox" />
<span data-bind=" text: value, attr: { for: key }" class="lbl padding-8 openSans-Text catchment-checkbox-span"></span>
</label>
The problem is that Coypu can't to find the hidden element on browser. And now I can't to check selected check-box or not.
This is standard check-box:
I turned off: opacity: 0 in CSS style.
And this is new checkbox with the new style.
How can I check the number of checked items in Coypu?
I can add ConsideringInvisibleElements = true inside SetUp method, but this option will be works always for all Tests. How I can change value of ConsideringInvisibleElements option on true or false when I need inside test code?
I'm find this variant:
var catchmentsCheckboxes = Browser.FindAllXPath("id('catchmentsColumn')/div[1]/div/label/input", null, new Coypu.Options { ConsiderInvisibleElements = true });
The first parameter: xPath to element;
The second parameter is can be null;
The third parameter is ConsideringInvisibleElements. And we can change value of this parameter on true or false.
Related
I am trying to convert an existing template from button clicks to a select with options. The original template looks like this:
<!-- ko foreach: {data: amounts, as: 'amount'} -->
<button type="button" data-bind="click: $parent.changeAmount.bind($parent)">
<span data-bind="text: amount.amountFormatted"></span>
</button>
<!-- /ko -->
The content of the array amounts is this:
[
{
"baseValue":"15",
"value":15,
"amountFormatted":"15,00 €",
"price":"15,00 €"
},
{
"baseValue":"25",
"value":25,
"amountFormatted":"25,00 €",
"price":"25,00 €"
},
{
"baseValue":"50",
"value":50,
"amountFormatted":"50,00 €",
"price":"50,00 €"
}
]
And this is the handler function:
changeAmount: function (amount) {
console.log(amount);
this.activeAmount(amount);
}
The console.log shows me how the return value of the button click looks like:
{
"baseValue":"50",
"value":50,
"amountFormatted":"50,00 €",
"price":"50,00 €"
}
Now I want this whole thing displayed as a select instead of buttons:
<select data-bind="options: amounts,
optionsText: 'amountFormatted',
optionsValue: 'value',
value: activeAmount,
event:{ change: changeAmount}"></select>
But with this template the select returns the entire view object instead of what a button click returns. How can I get the select to return the same object/array?
You should only be needing this as the minimal working sample:
The amounts observableArray with the options
The binding below:
<select data-bind="options: amounts,
optionsText: 'amountFormatted',
value: activeAmount"></select>
You are also using the event binding which is probably not needed on your context at all, you are binding it against the parent but instead of working with this you are also expecting the amount to be passed in, which does not work well with your click handler definition ( where you bind the function, ok, but no params are given if you go through that route ).
Rework your context and the click handler, so that it accesses activeAmount such that you dont expect a parameter. Since you are bound on the parent, just use this.activeAmount internally.
Note: you dont need to do anything to update the activeAmount if the select bind works properly. it will contain the seleced option's formattedAmount text already
I am using reactive forms.
I have a submit button that should be disabled until the form is valid:
<button type="submit" [disabled]="!_searchForm.valid && !_searchForm.pristine">Submit</button>
My fields can be toggled on/off using bools:
showName: boolean = true;
showPhone: boolean = true;
showCellphone: boolean = true;
And this is my validation rules:
this._searchForm = this._formBuilder.group({
name: [{value: '', disabled: !this.showName}, Validators.compose([Validators.minLength(3), Validators.maxLength(50), Validators.pattern('^[a-zA-Z]+$')])],
phone: [{value: '', disabled: !this.showPhone}, Validators.compose([Validators.minLength(3), Validators.maxLength(50), Validators.pattern('^[0-9-]+$')])],
cellphone: [{value: '', disabled: !this.showCellphone}, Validators.compose([Validators.minLength(3), Validators.maxLength(50), Validators.pattern('^[0-9]+$')])]
});
And finally, this is how each field is displayed in the HTML:
<div class="form-group" [ngClass]="{'has-danger': _searchForm.controls.name.errors && !_searchForm.controls.name.pristine}">
<label for="name">Name:</label>
<div class="input-group">
<span class="input-group-addon">
<div class="onofwrapper">
<div class="onoffswitch">
<input id="toggleName" type="checkbox" class="onoffswitch-checkbox" (click)='toggleName()' [checked]="showName">
<label class="onoffswitch-label" for="toggleName"></label>
</div>
</div>
</span>
<input type="text" formControlName="name" class="form-control" [ngClass]="{'form-control-danger': _searchForm.controls.name.errors && !_searchForm.controls.name.pristine}" autocomplete="off" spellcheck="false">
</div>
<div *ngIf="_searchForm.controls.name.errors && !_searchForm.controls.name.pristine" class="form-control-feedback">Error message</div>
If I don't touch the form I can submit, so pristine seems to be working.
The problem is, I can't enter text in just a single field and submit. If I enter text in one field, I have to enter text in all of them to be able to submit, or else _searchForm.valid won't return true even though I am not using Validators.required on all fields.
I have verified that each input "ships its own value", by removing the [disabled="!_searchForm.valid" line, and then just dumping out the values in my submit function like this:
console.log('Name: ' + this._searchForm.value.name);
console.log('Phone: ' + this._searchForm.value.phone);
console.log('Cellphone: ' + this._searchForm.value.cellphone);
What am I doing wrong?
Why does .valid require all fields in the form?
If you disable or enable an input, then, you need a function:
enableDisableInput(inputName: string): void {
if(!this._searchForm.controls[inputName].disabled) {
this._searchForm.controls[inputName].clearValidators();
this._searchForm.controls[inputName].disable();
} else {
this._searchForm.controls[inputName].setValidators(Validators.compose([Validators.minLength(3), Validators.maxLength(50), Validators.pattern('^[0-9]+$')])]);
}
this._searchForm.controls[inputName].updateValueAndValidity();
}
Invoked <input id="toggleName" type="checkbox" class="onoffswitch-checkbox" (click)='enableDisableInput("name")' [checked]="showName">
The manner in which the form building and validation is done with Reactive Forms means that you must manually clear and add validation even on disabled items (there may be plans to change this as it is a not uncommon complaint on the angular github). This is a code oriented and driven manner of forms and needs to be treated as such for the time being.
Whether or not the inputs are required is moot if they have an unmet minimum length. Reference https://github.com/angular/angular/pull/11450 which was recently included in Angular 2.0.2 https://github.com/angular/angular/blob/master/CHANGELOG.md
For forms driven it looks like they have a correction in 2.1.0 where those fields are optional with pattern and minlength but I don't know if that's also in Reactive Forms or not.
It turns out that this was a problem with input type="number". The fields containing phone and cellphone values was only supposed to contain numbers, so in addition to the Validators.pattern('^[0-9-]+$') validation I also gave them the input type of number.
As soon as that was changed into text, everything worked like expected.
I had the same issue with the Angular reactive forms. I was disabling and enabling my form controls based on some logic. It turns out I was disabling, but not enabling back the form controls, so I was getting a form.valid as false. Apparently in Angular's reactive forms a form with disabled fields is invalid and the docs are not mentioning this default behavior.
I have a main.controller.js where I want to check the value of a Checkbox. If the checkbox has been checked, the first flexbox will be shown and the second flexbox will not be shown in the fragment.
This my controller.js:
checkDone: function () {
var checkV = this.byId("ch1").getSelected();// not working
}
This my fragment.xml
<CheckBox id="ch1" select ="checkDone" text="Check"></CheckBox>
<FlexBox class="sapUiSmallMarginEnd" id="f1">
<Input value=""></Input>
</FlexBox>
<FlexBox direction="Column" id="f2">
<Input value=""></Input>
</FlexBox>
This code works (see example with sap.m.Checkbox here).
Just a recommendation: in your checkbox's 'select' handler you use:
this.byId("ch1").getSelected();
in order to whether the checkbox is selected or not, but this value is already given as a parameter of the select handler:
checkDone: function (oEvent) {
var bSelected = oEvent.getParameter('selected'));
}
Simmilar is for the sap.ui.commons.Checkbox API. Check change event.
It looks like the View.byId function returns an element in its initial form. When you find element from DOM, getSelected() function works as expected.
Instead of getSelected() try getChecked().
getChecked() will return true or false based on checked/unchecked.
I want to check my angular form validity with a little tweak,
I have a form builded dynamically with directives involved, Now the form has more than one page to it, so i play with ng-hide/ng-show when i move from page to page...
All i want to do is to check the validity of the first chunk of form inputs, for example:
I have 3 pages, 3 questions in every 'page', before the user can go to the next page, it should check for validation on the three inputs, and only than! he can move to the next one...
on my form tag i have 'novalidate' so i must do all the validations myself...
What you're after is ng-form
You can't nest HTML <form></form> tags but you can with ng-form to split your form into sections.
i.e.
<form name="myForm">
<ng-form name="subForm1">
<input name="txtField1" type="text" ng-model="Field1" ng-maxlength="50" required>
</ng-form>
<ng-form name="subForm2">
<input name="txtField2" type="text" ng-model="Field2" ng-maxlength="10" required>
</ng-form>
<button type="button1" ng-disabled="subForm1.$invalid" ng-click="doSomething() ">Button 1</button>
<button type="button1" ng-disabled="subForm2.$invalid" ng-click="doSomething()" >Button 2</button>
<button type="button3" ng-disabled="myForm.$invalid" ng-click="doSomething()" >Button 3</button>
</form>
In this instance button1 and button2 are disabled on parts of the form where as button3 is disabled based on the whole forms input
Source: https://docs.angularjs.org/api/ng/directive/ngForm
You can use the Angular's form element property $dirty, or you could check if the element you want to validate has the class ng-dirty.
If you'd like, read more here, it explains how to use and check this.
Angular JS has some pretty features which you can take advantage of especially the class .ng-valid and .ng-invalid. As the user fills your form, angular dose a real time update on the state of form fields by changing the classList to correspond to the current state of the form.
Any for field that is has been altered and does not pass the Angular validation will have a class .ng-invalid well all classes that passed the validation will have .ng-valid. While ng-pristine indicates that the form have not been modified ng-dirty tells you that the form has been modified. Not that ng-pristine and ng-dirty cannot be used to ascertain the validity of the field.
Meanwhile for your case I have created a CodePen
angular.module("paged", [])
.controller("FormCtrl", function($scope) {
$scope.form = {page: 1};
$scope.canShow = function(i) {
return (i === $scope.form.page);
};
$scope.submit = function(form) {
alert("Form Submitted", form);
};
$scope.gotoPage = function(pageTo) {
var show = false;
var els = document.getElementsByTagName("input"); //Just with input only to keep it simple
for (var i = 0; i < els.length; i++) {
if (els[i].hasAttribute("data-page") && els[i].getAttribute("data-page") == pageTo - 1) {
if (els[i].classList.contains("ng-invalid")) {
show = false;
break;
}
}
show = true;
}
if (show) {
$scope.form.page = pageTo;
if (pageTo == 4) {
$scope.submit($scope.form);
}
}
}
});
to show you how this can done. As someone will rightfully say, there may ways to kill a rat. I think this is one of them
I'm at a loss for how to do something extremely simple: Get the current value of a AutoComplete YUI3 widget. I have the following markup:
<label for="targets">Target:</label>
<input id="targets" type="text"></input>
<label for="packets">Packet:</label>
<input id="packets"></input>
I have the following Javascript:
YUI().use("autocomplete", function(Y) {
Y.one('body').addClass('yui3-skin-sam');
var tgt = new Y.AutoComplete({
inputNode: '#targets',
source: '/telemetry/targets?target={query}',
render: true
})
var pkt = new Y.AutoComplete({
inputNode: '#packets',
source: '/telemetry/packets?target='+tgt.get('value')+',packet={query}',
render: true
})
});
tgt.get('value') always returns an empty string no matter what I have typed into the #targets input. What am I doing wrong?
tgt.get('value') is the right way to get the current value of the inputNode, but in this case it's being called immediately when the value of the source attribute is set at instantiation, not when the request is made later. Since no text has been entered at this point, the value is empty.
If you want the "target" parameter of the second AutoComplete instance to be set to the current value of the first AutoComplete instance's inputNode, the best thing to do would be to set a custom requestTemplate for the pkt instance:
var pkt = new Y.AutoComplete({
inputNode: '#packets',
source: '/telemetry/packets',
requestTemplate: function () {
return '?query=' + encodeURIComponent(pkt.get('query')) +
'&target=' + encodeURIComponent(tgt.get('value'));
},
render: true
});
This will ensure that the query string of each request is generated at request time rather than at instantiation time.