Is there an Aurelia equivalent to Angular 2's local template variables? - javascript

In Angular 2 you can create local template variables to more easily access elements in the html.
<input #name type="text">
<button (click)="submit(name.value)">Submit</button>
Is there an equivalent functionality to this in Aurelia?

Yes- it's the ref attribute.
Here's an example: https://gist.run?id=7d1140ba81542bf7a2609a0d09fcdea5
app.html
<template>
<input ref="name">
<button click.delegate="submit(name.value)">Click Me</button>
</template>
app.js
export class App {
submit(name) {
alert(name);
}
}

Use ref
<input type="text" ref="name" />
<button click.delegate="submit(name.value)">Submit</button>
http://aurelia.io/docs#/aurelia/framework/1.0.0-beta.1.1.4/doc/article/cheat-sheet/5

Related

Is it possible to add a vue component to a traditional html form?

Is it possible to add a vue input component to a standard html form? I know this is not the ideal way to handle vue forms, but I'm curious about the possibility as a "quick and dirty" way for adding custom elements into pre existing html forms. Here's a hypothetical example:
<form action="/users" accept-charset="UTF-8" method="post">
<input type="email" name="user[email]" />
<input type="password" name="user[password]" />
<my-custom-fancy-vue-component />
<input type="submit"value="Sign up">
</form>
I'm wondering if the browser can read the value exposed by an input element withen the vue component and send that as a param when the user submit the form. Is there any other way to tell the browser how to access the value from a vue component if for example it doesn't use a native input internally, perhaps using a web component as a wrapper or using shadow dom?
Any <input> elements within the form should be included by the browser when the form is submitted. The browser won't care that the <input> is inside a Vue component.
For components that don't already have an <input> (or other suitable form element) you can add a hidden input, <input type="hidden">, to hold the value.
If the component you want to include is a third-party component then you won't be able to add the hidden input directly. However, you could still add it by using a wrapper component. The example below illustrates how you could handle that scenario.
const thirdPartyComponent = {
template: `
<button
#click="onClick"
type="button"
>
Increment {{ value }}
</button>
`,
props: ['value'],
methods: {
onClick () {
this.$emit('input', this.value + 1)
}
}
}
const myCustomFancyVueComponent = {
template: `
<div>
<third-party-component v-model="counter" />
<input type="hidden" :value="counter">
</div>
`,
components: {
thirdPartyComponent
},
data () {
return {
counter: 4
}
}
}
new Vue({
el: 'form',
components: {
myCustomFancyVueComponent
}
})
<script src="https://unpkg.com/vue#2.6.11/dist/vue.js"></script>
<form action="/users" accept-charset="UTF-8" method="post">
<input type="email" name="user[email]">
<input type="password" name="user[password]">
<my-custom-fancy-vue-component></my-custom-fancy-vue-component>
<input type="submit" value="Sign up">
</form>

Assigning value to a model in a handlebars template

I'm following this tutorial and any time it references an input element it defines them as so:
{{input type="text action='actionname'... }}
I'm told this is out of date and indeed the docs don't use that format, instead using this format:
<input type="text" {{action 'actionname' ... }}
I'm at the point of the tutorial where I'm saving data to the store. I've amended the tutorial to use angle brackets instead of curly braces like so:
<input type="text" value={{model.name}} class="form-control" placeholder="The name of the Library" />
<input type="text" value={{model.address}} class="form-control" placeholder="The address of the Library" />
<input type="text" value={{model.phone}} class="form-control" placeholder="The phone number of the Library" />
<button type="submit" class="btn btn-default" {{action 'saveLibrary' model}}>Add to library list</button>
My route looks like:
import Route from '#ember/routing/route';
export default Route.extend({
model() {
return this.store.createRecord('library');
},
actions: {
saveLibrary(newLibrary) {
newLibrary.save().then(() => this.transitionTo('libraries'));
},
willTransition() {
this.controller.get('model').rollbackAttributes();
}
}
});
When I call the route action saveLibrary and open the debugger, newLibrary doesn't have any data from the model properties. Whenever I change the handlebars template to use curly braces like the tutorial, it works fine; newLibrary contains name, address & phone.
What is the syntax for using angle brankets and having it propagate to route.js?
The angle bracket component should be <Input> not <input>.

Vue.js with $this.refs?

<template>
<div>
<form>
<p ref="uploadCvText" #click="openUploadFileDialogueCV(this.$refs.input_file_cv)">+ Upload Your CV (*)</p>
<input ref="input_file_cv" type="file" value="" name="input_file_cv" #change="handleCvUpload()">
</form>
</div>
</template>
<script>
methods: {
openUploadFileDialogueCV(e) {
e.click();
}
}
</script>
the problem is that (ref) is not allowed to be used in template ! so how can i
refer to html element and let openUploadFileDialogueCV() function
works correctly ?
Just don't use this in template, use #click="openUploadFileDialogueCV($refs.input_file_cv) instead

Angular Reactive Forms binding a control to multiple inputs doesn't refresh the others

When I am using reactive forms and try to access the same control in multiple Inputs it looks like it's only a one-way-data-binding (input-to-model).
If I edit an input it will update the model correctly but it will not refresh the other input as well.
<input type="text" formControlName="test" id="in1">
<input type="text" formControlName="test" id="in2">
My work-a-round is to add the following line to both inputs:
(change)="form.controls.test.setValue(form.controls.test.value)
But to be honest this looks like a pretty bad solution. Am I doing anything wrong here? What is the correct way to archive this?
https://plnkr.co/edit/yALzCIHgOA463OvGi5rP
I don't sure why you need exactly 2 fields with same formControlName but a solution could be - Create custom angular element.
#Component({
selector: 'custom-element',
templateUrl: `
<input type="text" [(ngModel)]="value">
<input type="text" [(ngModel)]="value">
`,
styleUrls: ['./custom-element.component.css']
})
export class CustomElementComponent implements ControlValueAccessor
#Input() value: any
writeValue(value: any) {
// Some if statements
this.value = value;
}
registerOnChange(fn: Function) {
// your code here
}
registerOnTouched(fn: Function) {
// your code here
}
And in the parent component template
<custom-element formControlName="fieldname"></custom-element>
For more details (and deeper explanation), you can check https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html
You can use ngModel:
<div>
<form [formGroup]="form">
<h2>Test = {{form?.controls.test.value}}</h2>
1. <input type="text" formControlName="test" [(ngModel)]="test">
2. <input type="text" formControlName="test" [(ngModel)]="test">
3.
<button type="button" (click)="form.controls.test.setValue('manual')">change with setValue</button>
</form>
</div>
The two-way binding syntax is really just syntactic sugar for a
property binding and an event binding
For example:
<app-sizer [(size)]="fontSizePx"></app-sizer>
Is equal to:
<app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer>
CODE EXAMPLE

Angular get form elements

I am trying to get element name and class from a form that is passed on to a function. How can i do that?
Html side.
<form name="test">
<div>
<input type="text" class="test1" name="test2"/>
</div>
<div>
<input type="text" class="test3" name="test4"/>
</div>
</form>
<div>
<input type="button" data-ng-click="save(test)" />
</div>
and Javascript side
$scope.save = function(form){
for(how many elements are there)
(get elements values)
}
how can I do that, can it even be done like that? My purpose is to change class and some other attributes when it's necessary.
You can access the form directly from $scope using its name, i.e. $scope.test, and the elements from the form, e.g. $scope.test.test2.
However, if you want to loop through the elements without having to know their individual names you can do something like:
angular.forEach($scope.test, function (element, name) {
if (!name.startsWith('$')) {
// element is a form element!
}
});
I'm relatively new to AngularJS, but I am going to make a solid attempt to answer to test my knowledge and hopefully help you.
So in your form, on each of your elements you should use a ng-model. For example, here is a form that may collect a users first and last name:
<form name="test">
<div>
<input type="text" class="test1" name="test2" data-ng-model="user.name/>
</div>
<div>
<input type="text" class="test3" name="test4" data-ng-model="user.last/>
</div>
</form>
<div>
<input type="button" data-ng-click="save(test)" />
</div>
This will allow you to access the data in your form through $scope.user.
Now for changing classes and attributes, I'm not sure what rules dictate a class/attribute change on your form, but you could use the ng-dirty class as a "flag" to watch for when the user makes a change. Some more information here as to what exactly you are trying to accomplish would be helpful.
A common piece of advice I've seen for angular.js is that, you should only do DOM manipulation in directives, so you should definitely consider doing it according to Anthony's answer, that is, using ng-model.
Go down below to see a way to do it more properly using directives.
But if you insist on doing it in the controller, here is a jsfidle that shows you how you can approach it:
http://jsfiddle.net/3BBbc/2/
HTML:
<body ng-app="myApp">
<div ng-controller="MyCtrl">
<form id="test">
<div>
<input type="text" class="test1" name="test2" />
</div>
<div>
<input type="text" class="test3" name="test4" />
</div>
</form>
<div>
<input type="button" ng-click="save('test')" value="submit" />
</div>
</div>
</body>
JavaScript:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.save = function (formId) {
$('#' + formId).find('input').each(function (idx, input) {
// Do your DOM manipulation here
console.log($(input).val());
});
};
}
And here is the jsfiddle showing you how to do it with directives. It's a bit more complicated though...:
http://jsfiddle.net/3BBbc/5/
I am trying to get element name and class from a form that is passed on to a function. How can i do that?
Your pseudocode is on the right track:
$scope.save = function( formName ) {
angular.forEach( $scope[ formName ], function( field, fieldName ) {
// Ignore Angular properties; we only want form fields
if( fieldName[ 0 ] === '$' ) {
return;
}
// "fieldName" contains the name of the field
// Get the value
var fieldValue = field.$viewValue;
} );
}
My purpose is to change class and some other attributes when it's necessary.
To do that, you can get the field elements, with the Angular element wrapper:
// Get the field element, as an Angular element
var fieldElement = angular.element( document.querySelector( '[name="' + fieldName + '"]' ) );
You can then use various jqLite methods on these elements. For instance, to set the element's class (overwriting the existing class), you can use the attr method:
// Replace existing class with "new-class"
fieldElement.attr( 'class', 'new-class' );

Categories

Resources