Binding ng model by key of loop issue - javascript

I'm trying to bind value to ng-model="" directive because I'm displaying elements with it in loop.
I tried like this
<div class="form-group">
<div data-ng-repeat="(key, n) in langInput.values">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 u-no-padding">
<label class="sell__label" for="auction_name_account_{{n.selected }}">Główna nazwa Twojej aukcji ({{n.selected }}):</label>
<div class="pst-relative">
<input type="text"
id="auction_name_account_{{n.selected }}"
class="form-control"
name="auction_name_account"
data-ng-model="inputs.auction_name_account[key]"
data-ng-minlength="10"
data-ng-maxlength="60"
required />
<span class="sell__input-text sell__input-text--big-input" data-ng-show="sellItem.auction_name_account.$error.required">Wymagane!</span>
<span class="sell__input-text sell__input-text--big-input" data-ng-show="sellItem.auction_name_account.$error.minlength">Za krótkie!</span>
<span class="sell__input-text sell__input-text--big-input" data-ng-show="sellItem.auction_name_account.$error.maxlength">Za długie!</span>
</div>
</div>
</div>
I need to have unique models to firstly create working validation (spans below) and to gather and send data to rest api later on.
This [key] somehow doesn't print as key of object which is number but as normal string as I see in console.
Data of langInput is
$scope.langInput = {
values: [
{
id: 1,
selected: "pl"
},
{
id: 2,
selected: "eng"
}
],
And I would like to have ng-model="inputs.auction_name_account[1]" where 1 is binded value or something similiar. Also above array of objects changes.

auction_name_account is going to be an Object when it's produced.
This means all property accessors must be a string and that properties which aren't a string, will be typecasted into one. This is why, while key is an integer, it will be casted as a string upon usage.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names

Related

In Angular, how can I disable the rest of the switches if one is selected?

I need some help. I'm trying to disable the rest of the switches if one is selected, as only one is allowed. I've tried doing loops approach but no success. Here is my code.
HTML file
<label class="switcher switcher-success ml-3">
<input
type="checkbox"
class="switcher-input"
(change)="registerProduct(i, $event.target.checked)"
/>
<span class="switcher-indicator">
<span class="switcher-yes">
<span class="ion ion-md checkmark"></span>
</span>
<span class="switcher-no">
<span class="ion ion-md-close"></span>
</span>
</span>
</label>
Ts file
public registerProduct(index, value) {
this.isChecked = value;
// tslint:disable-next-line: prefer-const
this.product = this.products[index];
if (value) {
this.includedProducts.push({
EntityTypeId: '49e185d1-529c-4b7a-a6fb-245649624a14',
EntityTypeName: 'Producto',
EntityId: this.product.ProductId,
EntityName: this.product.ProductName,
Required: true,
});
}
}
You can simply set the value of the checked element in your object.
I assume that you have an array of elements that you then show on your table.
On each elements you can add an attribute that is the checked value as follow
// Array element
let products = [{attribute1:value1,...},{...},...]
// If the array is created by you, just add the attribute by hand
// If you retrieve data from service or anywhere else, map all elements
products = products.map(product => {
return {...product, checked:false}
})
Once you have an array of elements that contains checked values, you can set them to the switches on your template
<label class="switcher switcher-success ml-3">
<input
type="checkbox"
class="switcher-input"
(change)="registerProduct(i, $event.target.checked)"
[checked]="{{value.checked}}" <!-- Here you set the value of your product -->
/>
<span class="switcher-indicator">
<span class="switcher-yes">
<span class="ion ion-md checkmark"></span>
</span>
<span class="switcher-no">
<span class="ion ion-md-close"></span>
</span>
</span>
</label>
So then, on your change method, you can set all the values for all products as false, and set the one identified by the index as true.
I have created a stackblitz to help you to understand.
Another aproach using only [ngModel] and (ngModel)
If you has a variable value you can use
<div *ngFor="let switch of switches">
<input type="checkbox"
[id]="switch.value"
<!--is disabled if our variable<>null and <>switch.value-->
[disabled]="value!=null && value!=switch.value"
<!--is true if our variable "value" is equal to switch.value-->
[ngModel]="value==switch.value"
<!--we equal the variable to switchValue if is checked or null if not-->
(ngModelChange)="value=$event?switch.value:null">
<label [for]="switch.value" [innerHTML]="switch.value"></label>
</div>
NOTE, you can omit the "disabled" if you want to have a serie of switch and only check one at time
To disable all other options when one of them is selected, you could use the following:
template
<div *ngFor="let switch of switches">
<input type="checkbox"
[id]="switch.value"
[disabled]="isSwitchDisabled(switch.value)"
[(ngModel)]="switch.checked">
<label [for]="switch.value" [innerHTML]="switch.value"></label>
</div>
controller
switches = [
{ value: 'First switch', checked: false },
{ value: 'Second switch', checked: false },
{ value: 'Third switch', checked: false },
{ value: 'Fourth switch', checked: false }
];
get selectedOptions() {
return this.switches
.filter(({ checked }) => checked)
.map(({ value }) => value);
}
get isSwitchDisabled() {
return (value: string) =>
this.selectedOptions.length && this.selectedOptions[0] !== value;
}
My example is generic and a bit simplistic, replace <label> with your ion markup and the model with whatever it is you're currently using.
I've demonstrated the principle:
the [disabled] attribute needs to be dynamic. I used a getter returning a function checking the value in real time.
See it working here
If the values of your switches are not unique, you'll probably want to add unique identifiers to them (e.g: id) and use those instead of value in both the id attribute of your <input>s and in the isSwitchDisabled function.

Not able to pass string to formGroup

1.I want to loop through an array
*ngFor="let item of myformNameArray"
Think myformNameArray.length have 3 items
If I console item it will be like
myFormName1
myFormName2
myFormName3
I have already made these form group in my typescript component.
Example
<form [formGroup]="myFormName3">
It will work perfectly!!
But i want to loop :means
<div *ngFor="let item of myformNameArray">
<form [formGroup]="{{item}}">
</form>
</div>
So when I do,
[formGroup]="{{item}}"
It throws me an error can't assign to object or interpolation
Or
[formGroup]="see(item)"
Where ,
see(item) :string {
return String(item);
}
ERROR TypeError: can't assign to property "validator" on "see(item)": not an object
[formGroup] requires a FormGroup Object not string
you need to make array of formgroups instead of string names
TS:
myformArray = [
this.myFormOne,
this.myFormTwo,
this.myFormThree
]
HTML:
<div *ngFor="let item of myformArray">
<form [formGroup]="item">
</form>
</div>
you can also use formArray instead of normal array
TS:
myFormArray = new FormArray([]);
this.myFormArray.push(myFormOne);
this.myFormArray.push(myFormTwo);
this.myFormArray.push(myFormThree);
HTML:
<div *ngFor="let form of myFormArray.controls;">
<form [formGroup]="form">
<input formControlName="controlOne" />
<input formControlName="ControlTwo" />
</form>
</div>
And also you should not use both square brackets and curly brackets (interpolation) for property binding, use either square brackets or interpolation.
internally angular converts square brackets to interpolation
either do this : [formGroup]="item"
or this : formGroup="{{item}}"
not both

Populating dropdownlist using knockout observable array

I am trying to bind 2 drop down lists to knockout observable arrays.The condition is that the first drop down list has to get populated first.The second drop down list is dependent on the first drop down list.Hence I am subscribing to the first drop down list to populate the second drop down list.
To try and achieve this,I have written the following code
HTML is
<div class="form-group">
<label class="col-sm-2 control-label labelfont">Certification:</label>
<div class="col-sm-6">
<select class="form-control" id="certification" name="certification" data-bind="value: certification, options: certificationArray, optionsText: 'Certification', optionsValue: 'CertificationID', optionsCaption: 'Select a Certification'">
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label labelfont">Specialization:</label>
<div class="col-sm-6">
<select class="form-control" id="specialization" name="specialization" data-bind="value: specialization, options: specializationArray,optionsText:'Specialization',optionsValue:'SpecializationId', optionsCaption: 'Select a Specialization'">
</select>
</div>
</div>
The view model is
self.specializationArray = ko.observableArray([]);
self.certificationArray = ko.observableArray([getCertifications()]);
self.certification = ko.observable("");
self.specialization = ko.observable("");
self.certification.subscribe(function () {
self.specializationArray([]);
getSpecializations();
}
});
The functions to get the respective certifications and speciaizations are
var getCertifications = function () {
$.getJSON("/Provider/GetCertifications", function (data) {
return data;
});
});
};
var getSpecializations = function () {
$.getJSON("/Provider/GetSpecializations/", { certificationID: $("#certification").val() }, function (data) {
self.specializationArray(data)
})
}
The JSON response looks like this
and the JSON looks like this
Could someone please guide me in the right direction,I am completely new to knockout and JSON.I am at my wit's end here.So,any help would be greatly appreciated.Thanks in advance.
In KnockOut, the values of the arrays are separate from the options the dropdowns get. You wouldn't change the observableArray, but the value observable itself. Better, though, would be to use a ko.computed field to hold the value of the 2nd dropdown.
I don't really understand why you think your dropdowns must get bound in a certain order, though. I'm not exactly sure how the Certifications and Specializations have to do with each other from your question. You aren't really doing anything in self.certification.subscribe(), like there was any dependency when filling in the Specialization. The JSON you supplied in the Certifications also does not have any related Specialization foreign key. But if your JSON for Certification looked like this:
[{"CertificationID": 1, "Certification": "M.B.B.S.", "SpecializationID": "7"},{"CertificationID": 2, "Certification": "M.D.", "SpecializationID": "3"}, ...]
while the JSON for Specialization looked like this...
[{"SpecializationID": 1, "Specialization": "Cardiology"},
{"SpecializationID": 2, "Specialization": "Dentistry"},
{"SpecializationID": 3, "Specialization": "General Practioner"}, ...
{"SpecializationID": 7, "Specialization": "Surgery"}
]
I believe something like this should work:
self.specialization = ko.computed(function() {
return ko.utils.arrayFirst(getCertifications(), function(certs) {
return certs.ID == self.SpecializationID();
}).SpecializationID;
});
But since I don't see where you have any dependencies, here, why not just fill them in, directly:
self.certificationArray = ko.observableArray(getCertifications());
self.specializationArray = ko.observableArray(getSpecializations());
self.certification = ko.observable(vm.certification);
self.specialization = ko.observable(vm.specialization);
And you set those values using the viewmodel returned from the dataset, which should be ID fields in your database table (CertificationID, SpecializationID).

Angular ng-options behaves odd

I have this typahead with angular strap:
<div class="form-group" ng-class="newGroupForm.placeReference.$invalid ? 'has-error' : ''">
<label for="placeReference" class="col-lg-2 control-label">Group Location</label>
<div class="col-lg-10">
<input type="text" name="placeReference"
ng-model="newGroup.reference"
ng-options="place.reference as place.name
for place in getPlaces($viewValue)"
bs-typeahead min-length="0" required >
</div>
</div>
getPlaces returns array of objects which looks like this:
{
reference: "ccj32213SIJD",
name: "some name",
}
When I am typing I am getting correct results, but when I select the wonted option the value that I see in my input is the reference (instead of the name).
Can any one point out my mistake?
Here is the controller code:
$scope.getPlaces = function(viewValue) {
var input = viewValue || $scope.currentPlace;
return googleService.placesAutocomplete(input).then(
function(places) {
return places;
}
);
};
If ng-options here behaves exactly like <select ng-options> (sorry, I'm not familiar with bs-typeahead directive), then you should change it to:
<input ...
ng-model="selectedPlace"
ng-options="place as place.name for place in getPlaces($viewValue)">
Then you can use get the name elsewhere:
<div>{{selectedPlace.name}}</div>
It's probably best to get the actual place object {name: "..", reference: "..."}, but if you just need the name, then you could do this:
<input ...
ng-model="selectedPlaceName"
ng-options="place.name as place.name for place in getPlaces($viewValue)">

Laravel 4 redirecting inputs back to page after validation fail

I have 4 fields that will be dynamically created by users.
<div class="controls" id="exchange-fields">
<p>
<div id='exchange_div'>
<div class="input-append" id='currency_div1'>
{{ Form::select('currency_id[]', $currencies, null, array('name'=>'currency_id', 'id'=>'currency_id', 'value'=>'Input::old("currency_id")[0]' )) }}
</div>
<div class="input-prepend" id='actual_div1'>
<span class="add-on">Actual</span>
{{ Form::text('exchange_rate[]', null, array('class'=>'input-medium rate', 'maxlength'=>10, 'id'=>'exchange_rate', 'value'=>'Input::old("exchange_rate")[0]' )) }}
</div>
<div class="input-append" id='markup_div1'>
{{ Form::text('exchange_rate_markup[]', null, array('class'=>'input-mini yellow rate', 'maxlength'=>4, 'id'=>'exchange_rate_markup', 'value'=>'Input::old("exchange_rate_markup")[0]' )) }}<span class="add-on">%</span>
</div>
<div class="input-prepend" id='rate_div1'>
<span class="add-on">Marked-up</span>
{{ Form::text('after_markup_rate[]', null, array('class'=>'input-medium yellow', 'maxlength'=>10, 'id'=>'after_markup_rate', 'value'=>'Input::old("after_markup_rate")[0]' )) }}
</div>
</div>
</div>
<div class="controls">
<input class="btn btn-primary" type="button" id="addScnt" value="Add">
</div>
I uses javascript to populate these fields dynamically.
var scntDiv = $('#exchange-fields');
var i = $('#exchange-fields p').size() + 1;
$('#addScnt').click(function() {
$(scntDiv).append('<p>');
$("#exchange_div").clone().attr("id",'exchange_div_'+ i).appendTo(scntDiv);
//Append the remove button
$($('#exchange_div_'+ i)).append('<input class="btn btn-primary" name="remove" type="button" id="remScnt" value="Remove">');
i++;
});
This is working perfectly until I POST these values to my controller and if validation fails.
How do I re populate those fields with the old input that are dynamically populated in my view file?
I use return Redirect::back()->withInput()->withErrors($e->getErrors()); to redirect after validation fail to repopulate those fields. But because these 4 fields only accept string values and the input returning back are in array so I am unable to repopulate these 4 fields after validation fails.
Any good ways to fix this?
Thanks in advance.
#a7omiton Instead of returning all inputs. I use Input::except(array) to return the rest of the fields which are not array.
While redirecting back I use an additional with() to return the array of fields like how you render your view when you load the page initially.
// If validation fails, ignore those exchange rate fields
//because they are in array not string
$input = Input::except([
'currency_id',
'exchange_rate',
'exchange_rate_markup',
'after_markup_rate'
]);
// return normally as separate array and it will store in session
return Redirect::back()
->withInput($input)
->withErrors($e->getErrors())
->with('exchange_rate', Input::get('exchange_rate'))
->with('currency_id', Input::get('currency_id'))
->with('exchange_rate_markup', Input::get('exchange_rate_markup'))
->with('after_markup_rate', Input::get('after_markup_rate'));
Don't set the value of the input fields in the HTML. Laravel will do this automatically when validation fails.
The second argument in Form::text is the value. Setting this to null will allow Laravel to automatically populate it.
laravel will autopopulate the form fields.
Just put second parameter with Input::old('column_name').
{{ Form::text('name', Input::old('name'), array('class' => 'span4','placeholder' => 'name')) }}
Though it is an old post, this will help some one land here looking for the solution.
You can get all the input variable in the view after a redirection by adding this code in your laravel view,
print_r(app('request')->old());
you can assign this values to your javascript variable, and populate the fields dynamically.

Categories

Resources