In Angular 2: How can I use an #Input to set a component's required attribute? - angular2-forms

I have a custom component in Angular:
#Component({
selector: 'spring-input',
template: `
<div class="group">
<input class="spring-input" type="text" [(ngModel)]="value" (blur)="onBlur()">
</div>
`
})
export class SpringInputControl implements ControlValueAccessor{
#Input() isrequired: boolean;
How can I setup the isrequired #Input for this component so that someone can set the input element's required attribute like this?
<spring-input name="testcomponent" [(ngModel)]="testcomponent" [isrequired]="true"></spring-input>
The HTML5 input element required attribute bugs out when I try setting it using curly braces {{required}}

Related

Using react-hook-form, how to programmatically modify values of inputs , depending on a selection?

Sounds simple, but I couldn't find a hello-world example of this, despite the richness of the doc. The closest I could find was in https://react-hook-form.com/advanced-usage, in the Working with virtualized lists section, but that relies on another module react-window, which introduces further complexity.
I want to allow the admin user to create-update-delete a list of products, with various properties.
My current code in JSX looks like this, I'd like to take advantage of error handling etc from react-hook-form:
<ol >
{products.map((row, index) => (
<li
className={index === selectedProductIndex ? "selected" : ""}
key={index}
id={index} onClick={handleSelectProduct}>
{row.name}
</li>
))}
</ol>
<form onSubmit={handleSaveProduct}>
<p>Product name: </p>
<input name="productName" type="text" value={selectedProductName}
onChange={handleEdit_name} />
(... more properties to edit here)
</form>
The handlers save the values of selectedProductName, selectedProductIndex, etc in useState, in a database via axios, etc.
I'm handling the values of each field individually in the useState, which I'm aware is laborious and heavy-handed.
Well the answer was quite simple, although it took me a while to figure it out.
In most of the examples, the onChange or onClick handlers don't use the event object, but nothing prevents you from adding it in. Then there's the setValue function to set the other control's value. Here's the code of a hello-world example. It offers one dropdown and one input field, the input field updates to match the selected value of the dropdown.
import React from "react";
import {useForm} from "react-hook-form";
function Test() {
const {register, handleSubmit, errors, setValue} = useForm();
const mySubmit = data => {
console.log(data);
}
return (
<div>
<form onSubmit={handleSubmit(mySubmit)} className="reacthookform">
<select name="dropdown" ref={register}
onChange={(ev) => setValue("productName", ev.target.value)}>
{["AAA", "BBB", "CCC"].map(value => (
<option key={value} value={value}>
{value}
</option>
))}
</select>
<input name="productName" defaultValue="AAA" ref={register({required: true})} className="big"/>
{errors.productName && <p className="errorMessage">This field is required</p>}
<input type="submit" value="Save product"/>
</form>
</div>
);
}
export default Test;

Set value to Vue model from rails rendering process

I create a complete rails application but I add the <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> a.k.a. Vue framework just for handling a few and specific tasks. One of those tasks is to controll a range input component like this:
_a_single_layout.html.erb
<div id="app">
<h1>{{progress}}%</h1>
<input type="range" min="0" max="100" v-model="progress">
</div>
application.js
let app = new Vue({
el: "#app",
data: {
progress: 0
}
})
What I get:
The problem is how to set the current stored value from the rails application here and at the same time, bind this value to the Vue model.
What I have tried:
<h1>{{progress = <%= #model.progress %>}}%</h1>
● This actually asigns the value just as I want but the range input get stuck.
<input type="range" min="0" max="100" v-bind:progress="<%= #model.progress %>">
● This moves the range to its expected position but stops refreshing the view when I move it with the mouse.
<input type="range" v-model="progress" v-bind:progress="<%= #model.progress %>">
● Set both, v-model and v-bind makes the last one be ignored.
let app = new Vue({
el: "#app",
data: {
progress: <%= #model.progress %>
}
})
● Also I have tried to write the value in the javascript side, but this is not a valid syntax for rails.
● I have looking for something like v-on:load="progress = <%= #model.progress %>" but doesn't seems v-on has any load event handler.
Here are the things I have tried on a pen: https://codepen.io/alex3o0/pen/XWrLwwm
I just go with a kind of tricky solution; I set my rails model variable to a Vue model variable wich get "stuck" but on the created method (using a setTimeout to delay the action ¯\_(ツ)_/¯) I reasign this value to a second and totaly free Vue model variable:
_a_single_layout.html.erb
<div id="app">
<span class="hide-me">{{real_value = <%= #model.progress %>}}</span><!-- this variable gets the value from the rails model but also gets "stuck" -->
<h1>{{progress}}%</h1>
<input type="range" min="0" max="100" v-model="progress"><!-- this variable will get its real value when the "created" method starts -->
</div>
application.js
let app = new Vue({
el: "#app",
data: {
progress: 0,
real_value: 0
},
created: function(){
setTimeout(() => this.progress = this.real_value, 1000)
}
})
By the way, I am still looking for a "correct" solution.
The solution is to create a Vue component.
Then you can pass your 'rails' data to Vue through this component with props. You just need to convert it to JSON first:
_a_single_layout.html.erb
<div id="app">
<load-progress :progress="<%= #model.progress.to_json %>"></load-progress>
</div>
application.js
const LoadProgress = Vue.component('load-progress', {
template: `
<div>
<p>{{ progress }}%</p>
<input type="range" min="0" max="100" :value="progress">
</div>`,
props: ['progress']
})
const app = new Vue({
el: '#app',
components: { LoadProgress }
})

Can I outsource a mat-form-field as a custom component or directive?

I have this form field:
<mat-form-field>
<input matInput type="password" placeholder="password" formControlName="password" autocomplete="new-password">
<mat-hint align="end">Must have one letter, and one number</mat-hint>
<mat-error *ngIf="password.invalid && password.touched" class="has-text-danger">
That password sucks...
</mat-error>
</mat-form-field>
And I want to use it as a custom component like:
<password-form-field formControlName="password"></password-form-field>
Giving the formControlName in the parent component. Is something like this possible?
The reason for this is that I would like to use this in many other components..
You should implement ControlValueAccessor in your password-form-field component in order to be able to use password-form-field with formControlName. Here is an example;
https://medium.com/#majdasab/implementing-control-value-accessor-in-angular-1b89f2f84ebf
.....
Alternatively you can achieve same result by using formControl directive instead of formControlName as follows:
First you should add an #Input to password-form-field
#Component({
selector: "password-form-field",
templateUrl: "./password-form-field.component.html",
styleUrls: ["./password-form-field.component.scss"]
})
export class PasswordFormFieldComponent {
#Input() formCtrl: FormControl;
constructor() {}
}
then use it in your password-form-field.component.html as follows:
<mat-form-field>
<input matInput type="password" placeholder="password" [formControl]="formCtrl" autocomplete="new-password" />
<mat-hint align="end">Must have one letter, and one number</mat-hint>
<mat-error *ngIf="password.invalid && password.touched" class="has-text-danger">
That password sucks...
</mat-error>
</mat-form-field>
Finally you can use it anywhere as follows;
/** if password is defined as a standalone FormControl */
<password-form-field [formCtrl]="password"></password-form-field>
OR
/** if password is defined in a FormGroup named myFormGroup */
<password-form-field [formCtrl]="myFormGroup.get('password')"></password-form-field>

How to set global variable in thymeleaf?

I am using thymeleaf in front end and I know variable concept in thymeleaf
<span th:with="var=${someValue}" th:text="${var}"></span>
if I use th:text the value in the variable will be printed and I can use that variable in the same element, Is there any way to use the var in other element like
<span th:with="var=${someValue}"></span>
<span th:text="${var}"></span>
I need to provide global scope to that variable is it possible in thymeleaf ?
Define var in the opening body tag
<body th:with="var=${var_value}">
Only nested item can see variable. Div tag is only an example. You can use tags you wants
<div th:with="var=${var_value}">
inside div tag var is visible.
</div>
Golobal variable is not supported in thymeleaf but it can be achieved through inline javascript.
Thymeleaf var_value stored in javascript variable 'value' and set the value in input field using JQuery.
<script th:inline="javascript">
/*<![CDATA[*/
$(document).ready(function (){
var Value = /*[[${var_value}]]*/ '';
$("#ID").val(Value);
});
/*]]>*/
</script>
<input type="text" class="order-entry" id="ID" placeholder="" th:value="${''}" />

Struggling to implement tabs in AngularDart

I am trying to learn Dart and AngularDart. Initially all was good until I decided to try and implement a tab component based on the example similar to the Angular home page e.g.
<tab>
<panel name="betty">
Content of betty tab
</panel>
<panel name="bob">
Content of bob tab
</panel>
</tab>
I have implemented following components.
#NgComponent(
selector: 'tab',
templateUrl: 'components/tab_component.html',
cssUrl: "http://netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css",
publishAs: 'ctrl'
)
class TabComponent {
List<TabPanelComponent> panes = new List();
add(TabPanelComponent tab) {
panes.add(tab);
}
}
#NgComponent(
selector: 'panel',
templateUrl: 'components/tab_panel.html',
publishAs: 'ctrl',
map: const {
'name': '#name'
}
)
class TabPanelComponent {
String name;
TabComponent tab;
TabPanelComponent(this.tab) {
tab.add(this);
}
}
And the following html templates
components/tab_component.html
<div class="tabble">
<ul class="nav nav-tabs">
<li ng-repeat="pane in ctrl.panes">{{pane.name}}</li>
</ul>
<div class="tab-content">
<content></content>
</div>
</div>
components/tab_panel.html
<div class="tab-pane">
<content></content>
</div>
When run, ctrl.panes in components/tab_component.html is empty, hence the list of tab names are not displayed. I can step through the code and see the panes being added to the list in TabComponent instance and the name attribute being set in the two instances of TabPanelComponent.
I feel that I am close but missing something obvious. Any pointers or advice that someone could offer to help a Dart newbie would be appreciated.
The NgComponent annotation for TabComponent was missing the visibility option. This should be changed from the default to CHILDREN_VISIBILITY
#NgComponent(
visibility: NgDirective.CHILDREN_VISIBILITY,
selector: 'tab',
templateUrl: 'components/tab_component.html',
cssUrl: "http://netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css",
publishAs: 'ctrl'
)
class TabComponent {
...
I've managed to implement a working tab component. Thing is, your approach and my approach are so similar I don't see the difference between them. Nonetheless, here's my working solution:
code at GitHub

Resources