Unable to assign variable from outer ngFor loop to ngModel inside a nested loop - angular2-forms

The problem I'm facing is setting ngModel's variable name using a variable. To elaborate:
The json being used here as 'options' is:
{
"a": [
"a1",
"a2",
"a3"
],
"b": [
"b1",
"b2",
"b3",
"b4"
],
"c": [
"c1",
"c2",
"c3",
"c4",
"c5",
"c6"
]
}.
The array 'keys' consists of {"a", "b", "c"} and has been created in the component class using -
this.keys = Object.keys(this.options);
What I'm doing here is creating different tabs on the html page for each key, with their values as radio buttons i.e. tabs are "a", "b" and "c" and each tab has corresponding values from options ("a1, a2, a3" on tab a, "b1, b2, b3 and b4" on tab b and so on) as radio buttons. It's working this far.
The problem pops up while trying to set the variable as the value of the key ("a", "b" and "c") and returning the corresponding selected radio button as the value for each tab. To clarify, I want to return a = a1 or a2 or a3 , b = b1 or b2 or b3 or b4 and c= c1 or c2 or c3 or c4 or c5 or c6 (based on my selection). I'm not able to set ngModel to any relevant variable to achieve this. I'm able to set ngModel to "a", "b" or "c" directly, but not using loop variables such as key or access keys using an index. Also, in case it is relevant, I'm using formGroup for this form.
Any help would be appreciated. I'm not sure if i've explained this well enough, so please feel free to ask questions. ( And I'm pretty new to Angular so I may have missed something obvious, though I've been trying to solve this for a while :/ )
<div *ngFor="let key of keys">
<md-tab label="{{key}}">
<fieldset class="fieldset">
<legend>{{key}}</legend>
<div class="row">
<div *ngFor="let opt of options[key]" class="large-3 small-6 columns end">
<input id="{{opt}}" type="radio" formControlName="{{key}}" value="{{opt}}" [(ngModel)]="key.selected" />
<label for="{{opt}}"><span class="{{opt}}"></span>{{opt}}</label><br/>
</div>
</div>
</fieldset>
</md-tab>

it is your starting point:
add in component
public temp = {};
and html
<div *ngFor="let key of keys">
<legend>{{key}}</legend>
<div *ngFor="let opt of options[key]">
<input id="{{opt}}" type="radio" [name]="key" [value]="opt" [(ngModel)]="temp[key]" />
<label for="{{opt}}"><span class="{{opt}}"></span>{{opt}}<br/></label>
</div>
</div>

Related

How do I get both auto-localized select list enums AND datatables in ABP Framework (abp.io)

In the ABP framework, the tutorial for version 5.1 says to:
Use Enum:enum-type:enum-value naming convention to localize the enum members.
e.g. "Enum:BookType:1": "Adventure"
However, this does not work when using the abp-select tag helper. I can see from the source code for abp-select that the expected format is actually:
Enum:enum-type.enum-toString
e.g. "Enum:BookType.Adventure": "Adventure"
So the documentation is inaccurate, but not a problem, as soon as I changed the resource file enums to the correct format abp-select localised the display values as expected.
However, the datatables source code for the Book List in the same tutorial then breaks:
columnDefs: [
{
title: l('Type'),
data: "type",
render: function (data) {
return l('Enum:BookType:' + data);
}
}
This code expects the enum format to be Enum:enum-type:enum-value and as data is passed back as an int and not the string representation of the enum, the datatable doesn't show the localised data.
As a work around, I am diverging from the tutorial instructions and binding the datatable to a BookDto where BookType is mapped to a string, not an enum. Feels a bit cludgy though.
Am I missing something here ABP?
Great product but this tutorial needs updating either way.
I ran into the same issue but solved it by updating the localization file en.json to match the enum value stored in the database and then changing the book.component.html file to match the abpLocalization property.
When I followed the official documentation at abp, I got this result:
First run with fallback string in HTML component
Acme.BookStore.Application.Shared/Localization/en.json
{
"culture": "en",
"texts": {
"Menu:Home": "Home",
"Welcome": "Welcome",
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.",
"Menu:BookStore": "Book Store",
"Menu:Books": "Books",
"Actions": "Actions",
"Close": "Close",
"Delete": "Delete",
"Edit": "Edit",
"PublishDate": "Publish date",
"NewBook": "New book",
"Name": "Name",
"Type": "Type",
"Price": "Price",
"CreationTime": "Creation time",
"AreYouSure": "Are you sure?",
"AreYouSureToDelete": "Are you sure you want to delete this item?",
"Enum:BookType.0": "Undefined",
"Enum:BookType.1": "Adventure",
"Enum:BookType.2": "Biography",
"Enum:BookType.3": "Dystopia",
"Enum:BookType.4": "Fantastic",
"Enum:BookType.5": "Horror",
"Enum:BookType.6": "Science",
"Enum:BookType.7": "Science fiction",
"Enum:BookType.8": "Poetry"
}
}
book.component.html in the angular project
<div class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
{{ '::Menu:Books' | abpLocalization }}
</h5>
</div>
<div class="text-end col col-md-6"></div>
</div>
</div>
<div class="card-body">
<ngx-datatable [rows]="book.items" [count]="book.totalCount" [list]="list" default>
<ngx-datatable-column [name]="'::Name' | abpLocalization" prop="name"></ngx-datatable-column>
<ngx-datatable-column [name]="'::Type' | abpLocalization" prop="type">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ '::Enum:BookType.' + row.type | abpLocalization }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'::PublishDate' | abpLocalization" prop="publishDate">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.publishDate | date }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'::Price' | abpLocalization" prop="price">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.price | currency }}
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
As you can see I have replaced the ":" with a "." as in the localization file.
After change to source-code I get this result:
Enums now translated correctly
I hope this helps you and others struggling with the same issue :)
I just had the same issue. The problem is a mismatch between the declaration of the localization file wrt the usage in the JS code.
In the localization file you can find keys like:
"Enum:BookType.Adventure": "Adventure"
while in the JavaScript it is used:
render: function (data) {
return l('Enum:BookType:' + data);
}
Thus either you change the localization keys as e.g. "Enum:BookType:Adventure": "Adventure" (with ':') or you change the code with this function:
render: function (data) {
return l('Enum:BookType.' + data);
}
where the '.' is concatenated instead of ':'

Rebo/Red parse: Is it possible to copy between two marks embedding nested div

Subsequent to Rebol/Red parse: how to copy between 2 marks let's now suppose I achieve to mark a string with some marks with a complex parse rule having nested div (whatever that rule), is there a general way to copy between mark1 and mark2, at least is there a specific way for this kind of nested div example:
{
<div>
a ; <- mark1
<div>
b
</div>
<div>
c
</div>
d ; <- mark2
</div>
<div>
e
<div>
f
</div>
<div>
g
</div>
h
</div>
}
rule: [
mark1:
...
mark2:
copy mark1 to mark2
]
This is no problem with the already shown solutions, but if you want to make it a little bit more complicated you could go back to an already defined / marked point in your src as in this example.
src: {1234567890abcdefghijklmnopqrstuvxyz}
>> parse src [ skip mark: to "a" mark2: :mark to "3" mark1: to end]
== true
>> mark1
== "34567890abcdefghijklmnopqrstuvxyz"
pay attention to :mark It set back the pointer to an prior defined point.
So the answer to your former question would look like that
rule: [
to "b" mark1: thru "e" mark2:
:mark1 copy text to mark2
]
Here replace "b" and "e" according your your wished points, maybe "a" and "d".

Cannot find control with path: angular2

I'm working on a model driven form and I can't get it to add items to a list being displayed with ngFor. I'm currently getting an error when trying to iterate the list.I tried all solutions available.
Error
Cannot find control with path: 'categories -> 0'
ts file
private categories : any= [{name: 'Strict',selected : false},
{name: 'Moderate',selected : true},
{name: 'Flexible',selected : true}];
let allCategories: FormArray = new FormArray([]);
for (let i = 0; i < this.categories.length; i++) {
let fg = new FormGroup({});
fg.addControl(this.categories[i].name, new FormControl(this.categories[i].selected))
allCategories.push(fg)
}
form initialization
categories: allCategories,
Html part
<div formArrayName="categories">
<div *ngFor="let category of categories; let i=index">
<span formGroupName="{{i}}">
<label>
<input type="checkbox" formControlName="{{category.name}}"/>
{{category.name}}
</label>
</span>
</div>
</div>
#Jadoon, I suppose, #DineshArun meant that he wants to list all categories using reactive approach and uses for that FormArray with FormGroups for each category.
The problem is that Angular usually assigns array index as group name by default 0, 1...
But in #DineshArun's case that doesn't work. And in mine case it didn't too, but I've found the solution.
First of all, look at this question and it's marked answer. Rewrite the filling in of your formArray that way, and then assign to formControlName the raw name of the control, which you pointed in your patch() method.

What is the proper way to implement ionic radio buttons for voiceover screen reader?

I have the following radio button list that works without voiceover enabled:
<ion-list>
<label class="item item-radio"
ng-repeat="type in someCtrl.types"
aria-label="{{type.label}}"
id="{{type.value}}">
<input type="radio"
role="radio"
ng-model="someCtrl.data.type"
ng-value="type.value"
aria-labelledby="{{type.value}}">
<div class="radio-content">
<div class="item-content">{{type.label}}</div>
<i class="radio-icon ion-checkmark"></i>
</div>
</label>
</ion-list>
When I enable voiceover and select an item from the list, the item receives a checkmark, but the model doesn't change and the default item selected still retains its checkmark. As a user continues to select items from the list, they each get a checkmark but the data model doesn't change and all checkmarks are retained. Has anyone had any luck implementing ionic radio lists that work with voiceover?
Step1: In controller first initialise the list of items where you are going to select
For Ex:
$scope.audio_types = [
{name: $translate.instant("Morning"), value : 'Morning'},
{name: $translate.instant("Afternoon"), value : 'Afternoon'},
{name: $translate.instant("Evening"), value : 'Evening'}
];
Step2 : You are using an ng-model so initialise the object with an empty properties
For Ex: $scope.profile = {};
Step3: You are using radio button to select an item property so declare the method to check wether the property is changing or not
$scope.roundCountChange = function(){
console.log($scope.profile.dropdown);
}
Step4 : Final Step in your HTML Page add these code
<label class="item"> "select" <br/>
<label ng-repeat="item in audio_types">
<input type="radio" ng-model="profile.dropdown" ng-value="item.value" ng-change="roundCountChange()"/> item.name
</label>
</label>

Rebinding a list of textboxes in ASP MVC2 VS2010 Beta2 after postback

So.. I have a problem. I'm sure almost anybody that tried MVC has had it. Nevertheless I've been unsuccessfull in googling a solution or thinking of one for my self.
The problem is this: I have a list of textboxes that I'd like to edit all at once, and I'd also like to add new items to my list. However, the text binding fails after the first postback.
So I've made a small example to illustrate the problem:
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<% foreach(string s in Model) { %>
<p>
<%= Html.TextBox("list",s) %>
</p>
<% } %>
<p>
<%= Html.TextBox("newstr") %>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
The controller code:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Edit()
{
return View(new List<string>() { "aa", "bb", "cc" });
}
// Remove empty strings and add the new one
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(List<string> list, string newstr)
{
List<string> res = list.Where(s => !string.IsNullOrWhiteSpace(s)).ToList();
if (!string.IsNullOrWhiteSpace(newstr))
res.Add(newstr);
return View(res);
}
So, on first GET i return the 3 strings aa, bb and cc, and get 3 textboxes with their text in, as well as en empty textbox for new strings, like this:
aa
bb
cc
Empty.
Now, if I clear the bb string and add "dd" in the empty textbox, I get a return list of "aa","","cc", and "dd" in newstr. This returns a new list of "aa", "cc", "dd" which is what I would expect to see in my checkboxes. Instead I get:
aa
aa
aa
dd (expected empty)
So.. There is something fundamental I didn't get :) Why does it ignore my new datamodel and use some of the old and not all?
I suppose its some kind of viewstate leftover from asp.net, so how do I turn it off? I really want the stateless webpage as advertised.
If you look at your html source you will see that this has nothing to do with viewstate. When filling inputs after a post the framework will first search the posted values and fill your inputs based on that. Thats why you will get "dd" in your last input. The reason why you get "aa" in the rest of the inputs is that they all have the same name. Your post will look something like this:
list = "aa", list = "", list = "cc"
So when you render a input with the name "list" the framework will search that post and take the first value that matches. This will be "aa" every time. Thats why you get "aa" in all your inputs. You should not have multiple <input type="text" /> with the same name. With unique names you will fix the issue with the looped inputs.
I'm not sure if there is a way to make a <%=Html.TextBox()%> not look in the posted data. But you can always change it to a regular <input type="text" name="newstr" /> and that will work.
Interesting problem. There seems to be a problem inside Html.TextBox(). I debugged your code, and as you can see, the Model in the View does contain the correct List. (BTW, I tested this in Visual Studio 2008).
When you convert the
<%=Html.TextBox("list", s) %>
to a standard
<input id="list" name="list" value="<%=s %>" />
it works like it should work. Is this an option?

Resources