Angular 2 Reactive Forms - Detect input change event on component - angular2-forms

I would like to detect the value of change event to the input on form.component.ts.
I would not like to call the function ex: (onChange) = "function($event.target.value)"
public form: FormGroup;
constructor(private formBuilder: FormBuilder){
}
private loadForm(){
this.form = this.formBuilder.group({
tipo: [null, Validators.required],
nomeRazao: [null, Validators.compose([Validators.required, Validators.minLength(3), Validators.maxLength(64)])],
apelidoFantasia: [null, Validators.compose([Validators.required, Validators.minLength(3), Validators.maxLength(64)])],
cpfCnpj: [null, Validators.compose([Validators.required, Validators.minLength(11), Validators.maxLength(14)])],
rgIe: [null],
contato: this.formBuilder.group({
email: [null],
telefone: [null]
}),
endereco: this.formBuilder.group({
cep: [null, Validators.pattern('^([0-9]){5}([-])([0-9]){4}$')],
uf: [null],
cidade: [null],
bairro: [null, Validators.required],
logradouro: [null],
complemento: [null],
numero: [null, Validators.pattern('/^\d+$/')]
})
});
}
ngOnInit() {
this.loadForm();
}

You can subscribe to your form changes by using this :
this.form.valueChanges.subscribe(() => {
if (this.registerForm.controls['yourControlName'].value === 'someValue') {
//
}
});

For detecting changes in value of a particular field, 'valueChanges' event on that field can be subscribed, as shown below:
this.myForm.get('formcontrolname').valueChanges.subscribe(val => {
this.message = val;
});

For people who are checking for higher versions of Angular or to whom the accepted solution isn't working,
Try this
this.myForm.valueChanges.subscribe(val => {
this.message = val.formcontrolname;});
the approach is to use the variables inside the change detection and you can restrict it with the respective form control name

Related

How to prevent select2 to call select2:close the second time when selectOnClose is set to true?

I am using Select2 V. 4.0.10
I want to have a select2 that behaves the same way when you select using the Enter key and the Tab key.
What happens is that when selecting using the Tab key, the close event is called twice, which is not what was intended to do.
var data = [
{ id: 0, text: 'New' },
{ id: 1, text: 'In Process' },
{ id: 2, text: 'Draft' },
{ id: 3, text: 'Submitted' },
{ id: 4, text: 'Deleted' }
];
$(".test").select2({
allowClear: true,
selectOnClose: true,
data: data,
placeholder: "Select a status"
});
$("select.test", "body").off("select2:close").on("select2:close", function (e){
// This is called twice
console.log("select2:close");
});
select.test {
width: 200px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/css/select2.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/js/select2.min.js"></script>
<select class="test"></select>
Here are the sequences of the select2 events that are triggered when selecting with the Tab/Enter key.
TAB
select2:opening
select2:open
select2:closing
select2:selecting
change
change.select
select2:closing
select2:close
select2:select
select2:close
ENTER
select2:opening
select2:open
select2:selecting
change
change.select
select2:closing
select2:close
select2:select
As the pattern in always the same, the solution was to create a variable that would be toggled on when select2:select was triggered, and use that to see if it was be used before.
Notice, instead of using the global window object you should rather use a class variable or a prototype property to store this boolean.
var data = [
{ id: 0, text: 'enhancement' },
{ id: 1, text: 'bug' },
{ id: 2, text: 'duplicate' },
{ id: 3, text: 'invalid' },
{ id: 4, text: 'wontfix' }
];
window._select2Select = false;
$(document).on('select2:select', "select", function (e) {
window._select2Select = true;
});
$(".test").select2({
allowClear: true,
selectOnClose: true,
data: data,
placeholder: "Select a status"
});
$("select.test", "body")
.off("select2:close")
.on("select2:close", function(e) {
if(window._select2Select){
window._select2Select = false;
return;
}
console.log("select2:close");
window._select2Select = false;
});

Formarray doesnt show all the records received from service/api

I am trying to patch the object received from webapi to an angular reactive form. The form also has a formarray. But, despite having more than 3 or more records only 2 records are being patched to the formarray of the reactive form.
I have two entities noseries and noseriesList, where a noseries has zero or many noseriesLists. So after obtaining noseries from webapi, i want to patch properties and navigation list "noseriesLists" of noseries into reactive form.
Rest of the properties are being patched properly, but only 2 records of navigation list "noseriesLists" is being patched to the formArray nested inside the reactive form.
//initialization of form
this.noseriesForm = this.fb.group({
id: [null],
description: ['', Validators.required],
code: [ '', Validators.compose([Validators.maxLength(10), Validators.required])],
noSeriesList: this.fb.array([
this.initLine(), this.initLine()
])
});
//patching the object received from service to form
this.route.params.subscribe(routeParam => {
if (routeParam.id) {
this.noseriesService.get(routeParam.id)
.subscribe((data: NoSeries) => {
this.isCreateMode = false;
this.noseries = data;
this.noseriesForm.patchValue(this.noseries);
console.log(this.noseries, 'data from api');
console.log(this.noseriesForm.value,'formvalue');
});
}
});
//initialise formArray
initLine(): FormGroup {
return this.fb.group({
id: [null],
startingNoSeries: ['', Validators.required],
endingNoSeries: '',
lastUsedSeries: '',
effectiveDate: [null],
endingDate: [null],
noSeriesId: [null]
});
}
logging the data received from service shows 3 noseriesList records, whereas logging formvalue only shows 2 records of noseriesList.
while you are initializing the form array for the first time you are adding two empty controls. that's why when you patch value to formgroup, only those two empty controls get filled. you should fill the formarray with number of controls that is going to be patched before patching a value.
//patching the object received from service to form
this.route.params.subscribe(routeParam => {
if (routeParam.id) {
this.noseriesService.get(routeParam.id).subscribe((data: NoSeries) => {
this.isCreateMode = false;
this.noseries = data;
const nsList = this.noseriesForm.get("noSeriesList") as FormArray;
nsList.clear();
this.noseries.forEach(_ => nsList.push(this.initLine()));
this.noseriesForm.patchValue(this.noseries);
console.log(this.noseries, 'data from api');
console.log(this.noseriesForm.value,'formvalue');
});
}
});

Angular2 Async validator

Sorry for my bad english.
I'm trying to use a custom async validation in my angular application like this
asyncValidator(control:FormControl):Promise<any>{
const promise = new Promise<any>(
(resolve, reject) =>{
setTimeout(() => {
console.log("it works");
resolve(null);
},5000);
}
);
return promise;
}
I declared my reactive form like this:
this.customForm = this.formbuilder.group({
'userData': this.formbuilder.group({
'name': ['',this.asyncValidator],
'email': [''],
}),
'pass': [''],
'gender': ['male'],
'hobbies': this.formbuilder.array([
['Reading']
])
})
Even though, the asyncValidator always resolve(null), the name input still has ng-invalid class.
You incorrectly placed your async validator.
It should be:
'name': ['', null, this.asyncValidator],
(1) (2) (3)
where:
(1) - control value
(2) - sync validator
(3) - async validator
Stackblitz example

How to initialize the selection for rails-select2 in BackboneForms schema?

The project uses marionette-rails, backbone-on-rails, select2-rails and this port to BackboneForms to provide a multiselect form field. The select options are available to the user. They are retrieved from the collection containing the total list of options:
MyApp.module("Products", function(Products, App, Backbone, Marionette, $, _) {
Products.CustomFormView = Products.CustomView.extend({
initialize: function(options) {
this.model.set("type", "Product");
Products.EntryView.prototype.initialize.apply(this, arguments);
},
schemata: function() {
var products = this.collection.byType("Product");
var productTypes = products.map(function(product){
return {
val: product.id,
label: product.get("name")
};
});
return {
productBasics: {
name: {
type: "Text",
title: "Name",
editorAttrs: {
maxLength: 60,
}
},
type: {
type: 'Select2',
title: "Product type",
options: {
values: productTypes,
value: [3, 5],
initSelection: function (element, callback) {
var data = [];
$(element.val().split(",")).each(function () {
data.push({id: this, text: this});
});
callback(data);
}
},
editorAttrs: {
'multiple': 'multiple'
}
}
}
};
}
});
});
Do I initialize the value correctly in options.value? How comes initSelection is never called? I copied the function from the documentation - it might be incomplete for my case. None of the products with the IDs 3 and 5 is displayed as the selection.
initSelection is only used when data is loaded asynchronously. My understanding is that there is no way of specifying the selection upon initialization if you are using an array as the data source for a Select2 control.
The best way of initializing the selection is by using setValue after the form is created. Here is a simplified example based on the code in your example.
var ProductForm = Backbone.Form.extend({
schema: {
type: {
type: 'Select2',
title: "Product type",
options: {
values: productTypes,
},
editorAttrs: {
'multiple': 'multiple'
}
}
});
var form = new ProductForm({
model: new Product()
}).render();
form.setValue("type", [3, 5]);
You can use value function (http://ivaynberg.github.io/select2/#documentation) in setValue. I personally recomend you to use this backbonme-forms plugin: https://gist.github.com/powmedia/5161061
There is a thread about custom editors: https://github.com/powmedia/backbone-forms/issues/144

Backbone.js - How to save model by form and post to server

I'm n00b in BackboneJS/RequireJS and I'm developing an web app that use a RESTful API.
So I've a model like this:
models/pet.js
define([
'backbone'
], function(Backbone){
var PetModel = Backbone.Model.extend({
urlRoot: 'http://localhost:3000/pet',
idAttribute: '_id',
defaults: {
petId: "",
type: "",
name: "",
picture: "",
description: "",
breed: "",
size: "",
sex: "",
age: "",
adopted: false,
}
});
return PetModel;
});
a collection: collections/pets.js
define([
'backbone',
'models/pet'
], function(Backbone, PetModel){
var PetsCollection = Backbone.Collection.extend({
url: 'http://localhost:3000/pets',
model: PetModel,
});
return PetsCollection;
});
And a view that renders a form to add new models (Maybe it's possible another way more elegant)
views/petAddNew.js
define([
'jquery',
'backbone',
'models/pet',
'collections/pets',
'text!templates/pet/addNew.html'
], function($, Backbone, PetModel, PetsCollection, petAddNewTemplate){
var PetAddNewView = Backbone.View.extend({
el: $('#formAdd'),
template: _.template(petAddNewTemplate),
events: {
'click #add' : 'submitAdd',
},
initialize: function() {
this.model = new PetModel();
this.collection = new PetsCollection();
_.bindAll(this, 'submitAdd');
},
render: function() {
var view = this;
view.$el.html( view.template );
return view;
},
submitAdd: function(e) {
//Save Animal model to server data
e.preventDefault();
var pet_data = JSON.stringify( this.getFormData( this.$el.find('form') ) );
this.model.save(pet_data);
this.collection.add(this.model);
return false
},
//Auxiliar function
getFormData: function(form) {
var unindexed_array = form.serializeArray();
var indexed_array = {};
$.map(unindexed_array, function(n, i){
indexed_array[n['name']] = n['value'];
});
return indexed_array;
},
});
return PetAddNewView;
});
So when I submit the form I don't post any data to server. I don't know how to fix it.
Any ideas? Thanks in advance!
You need set the attributes first and then save.
//Auxiliar function
getFormData: function(form) {
var self = this;
var unindexed_array = form.serializeArray();
$.map(unindexed_array, function(n, i){
self.model.set({
n['name']: n['value']
});
});
}
Now this.model.save() works (saving on the server side).
You can see it work in a fiddle.
Model.save expect an object/hash of new values, just like Model.set. Here you're passing a string as the attributes arguments.

Resources