I am a very new user of Angualr and currently using Angular 10. I want the textarea field that should be empty after click on the clear button. But this code is not working that I want to do. Could someboday help me.
Thanks.
HTM file
<button (click)="ClearField()" type="button">clear field</button>
<textarea class="form-control rows=10 cols=50 cstm-textarea" #box (keyup)="OnUpdateTextArea(box.value)">
</textarea>
.ts file
export class AppComponent {
str = '';
OnUpdateTextArea(value: string) {
this.str = value;
console.log("text area value:", this.str);
}
ClearField() {
this.str = '';
}
}
Believe binding can fix this problem.
<button (click)="ClearField()" type="button">clear field</button>
<textarea [(ngModel)]="str" class="form-control rows=10 cols=50 cstm-textarea">
</textarea>
and ts I believe can stay the same.
You should look into one way and two way binding
The solution of this problem:
<button (click)="ClearField(box)" type="button">clear field</button>
<textarea class="form-control rows=10 cols=50 cstm-textarea" #box (keyup)="OnUpdateTextArea(box.value)">
</textarea>
Related
I was trying to add additional custom field in the checkout screen and here is my code:
<div class="additional-checkout-fields" style="display:none">
<div class="fieldset fieldset--address-type" data-additional-fields>
<div class="field field--optional field--address-type">
<h2 class="additional-field-title">ADDRESS TYPE</h2>
<div class="field__input-wrapper">
<label>
<input data-backup="Residential" class="input-checkbox" aria-labelledby="error-for-address_type" type="checkbox" name="checkout[Residential]" id="checkout_attributes_Residential" value="Residential" />
<span>Residential</span>
</label>
<label>
<input data-backup="Commercial" class="input-checkbox" aria-labelledby="error-for-address_type" type="checkbox" name="checkout[Commercial]" id="checkout_attributes_Commercial" value="Commercial" />
<span>Commercial</span>
</label>
</div>
</div>
</div>
</div>
<script type="text/javascript">
if (window.jQuery) {
jquery = window.jQuery;
} else if (window.Checkout && window.Checkout.$) {
jquery = window.Checkout.$;
}
jquery(function() {
if (jquery('.section--shipping-address .section__content').length) {
var addType = jquery('.additional-checkout-fields').html();
jquery('.section--shipping-address .section__content').append(addType);
}
});
</script>
It returns the checkout page like this -
The problem is - once I click continue button and comes back to this page again, I don't see the checkbox checked. I feel the values are not being passed or may be something else.
What am I missing?
From the usecase, it looks like you want the user to select the Address Type either Residential or Commercial so a raido button group seems more suitable. I have edited the HTML to create the Radio Button instead of Checkbox. To maintain the state, I have used Session Storage. You may also replace Session Storage with Local Storage if you want to do so. For explanation check code comments.
<div class="additional-checkout-fields" style="display:none">
<div class="fieldset fieldset--address-type" data-additional-fields>
<div class="field field--optional field--address-type">
<h2 class="additional-field-title">ADDRESS TYPE</h2>
<div class="field__input-wrapper">
<label>
<input class="input-radio" aria-label="" type="radio" name="checkout[address_type]" id="checkout_attributes_Residential" value="residential" checked>
<span>Residential</span>
</label>
<label>
<input class="input-radio" aria-label="" type="radio"name="checkout[address_type]" id="checkout_attributes_Commercial" value="commercial">
<span>Commercial</span>
</label>
</div>
</div>
</div>
</div>
JavaScript part
<script type = "text/javascript" >
if (window.jQuery) {
jquery = window.jQuery;
} else if (window.Checkout && window.Checkout.$) {
jquery = window.Checkout.$;
}
jquery(function() {
if (jquery('.section--shipping-address .section__content').length) {
var addType = jquery('.additional-checkout-fields').html();
jquery('.section--shipping-address .section__content').append(addType);
// Get saved data from sessionStorage
let savedAddressType = sessionStorage.getItem('address_type');
// if some value exist in sessionStorage
if (savedAddressType !== null) {
jquery('input[name="checkout[address_type]"][value=' + savedAddressType + ']').prop("checked", true);
}
// Listen to change event on radio button
jquery('input[name="checkout[address_type]"]').change(function() {
if (this.value !== savedAddressType) {
savedAddressType = this.value;
sessionStorage.setItem('address_type', savedAddressType);
}
});
}
});
</script>
You are responsible for managing the state of your added elements. Shopify could care a less about stuff you add, so of course when you flip around between screens, it will be up to you to manage the contents. Use localStorage or a cookie. Works wonders. As a bonus exercise, ensure that your custom field values are assigned to the order when you finish a checkout. You might find all your hard work is for nothing as those value languish in la-la land unless you explicitly add them as order notes or attributes.
I am creating a set of radio buttons in Aurelia with the code like this:
<div repeat.for="option of options">
<input type="radio" id="${option}_id" name="radio_options" model.bind="option" checked.bind="optionValue"/>
<label for="${option}_id" id="${option}_label">${option}</label>
</div>
However, doing it this way I discovered that model.bind is not working - the optionValue in corresponding class is not populated when radio button is checked. Similarly when some value is assigned to optionValue in the class, the appropriate radio button is not checked. I found this happening only with repeater. Options are numbers in my case. Could you please help me to find out what may be wrong here?
The first problem is that model.bind should be used when working with objects. Since you're working with a primitive type, you should use value.bind instead.
The second problem is that input values are always strings, so when setting an initial value, it must be a string. For example:
Html:
<template>
<div repeat.for="option of options">
<input type="radio" id="${option}_id" name="radio_options" value.bind="option" checked.bind="optionValue"/>
<label for="${option}_id" id="${option}_label">${option}</label>
</div>
<p>Selected Option: ${optionValue} </p>
</template>
JS:
export class App {
options = [ 1, 2, 3, 4 ]
optionValue = '3';
}
If you really want to use int in your view-model, you can create a ValueConverter to convert the value to int when passing it to/from the view. For instance:
export class AsIntValueConverter {
fromView(value) {
return Number.parseInt(value);
}
toView(value) {
return value.toString();
}
}
Usage:
<input type="radio" id="${option}_id" name="radio_options" value.bind="option" checked.bind="optionValue | asInt"/>
Running Example https://gist.run/?id=1465151dd5d1afdb7fc7556e17baec35
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 got some hidden buttons on the page. When I click on text input, one of these buttons shows on the page. Before:
<div field='login'>
<input type="text">
<button class="submit" style="display: none">Save</button>
</div>
<div field='name'>
<input type="text">
<button class="submit" style="display: none">Save</button>
</div>
After click on second input:
<div field='login'>
<input type="text">
<button class="submit" style="display: none">Save</button>
</div>
<div field='name'>
<input type="text">
<button class="submit">Save</button>
</div>
So I try to interact with second button by next selectors in my test:
static content = {
submitButton { $("button.submit") }
}
but I have next error:
isorg.openqa.selenium.ElementNotVisibleException: Element is not currently visible and so may not be interacted with
If I write:
static content = {
submitButton { $("button.submit", 1) }
}
it works, but I need to work with one first visible button on the page. What is wrong?
Unfortunately there is no css selector to find visible elements but you can use displayed property of Navigator and its findAll() method to find the button that is visible:
static content = {
submitButton { $("button.submit").findAll { it.displayed } }
}
I have a Form and i want to disable the entire form on click of a Button ,please see this code
<div dojoType="dijit.form.Form" id="myForm" jsId="myForm" encType="multipart/form-data"
action="" method="">
<table>
<input type="text" id="name" name="name" required="true" dojoType="dijit.form.ValidationTextBox"
<input type="text" id="dob" name="dob" dojoType="dijit.form.DateTextBox"
</table>
<button dojoType="dijit.form.Button" type=button onClick="console.log(myForm.getValues())">
Get Values from form!
</button>
<button dojoType="dijit.form.Button" type="submit" name="submitButton"
value="Submit">
Submit
</button>
<button dojoType="dijit.form.Button" type="reset">
Reset
</button>
<button dojoType="dijit.form.Button" onClick="callMe()">
Disable IT
</button>
</div>
I have written a function callMe to disable this
function callMe()
{
dijit.byId('myForm').disabled=true;
}
Dijit forms do not have a property "disabled", but rather you have to overwrite the onSubmit event:
dijit.byId('myForm').onSubmit = function () {
// If we return false here, the form will not be submitted.
return myMagicEnabledFlag;
};
Note that you cannot use dojo.connect as you have to modify the return value of the event and not just connect to it.
For disabling the entire form elements, use the "getChildren()" function of the dijit form, which would return the array of all the field widgets of that corresponding form. Then, you need to disable the widgets of that array. See below sample:-
dijit.byId('myForm').onSubmit = function () {
var widgets = dijit.byId('myForm').getChildren();
for(var i=0;i<widgets.length;i++) {
widgets[i].set('disabled', true);
}
//if you need to prevent the form submission & just disable, return false,
//else ignore the following return stmt
return false;
};