Html
<input type="text" class="fulltextbox saving_field" dataid="1" dataname="temperature" dataunit="° F" ng-model="addVt.Temp.value" />
js
var tData = [];
angular.forEach(angSel('.saving_field'), function(v, k){
console.log(v.dataname);
tData.push({id: v.dataid, name: v.dataname, value: v.value, unit: v.dataunit});
});
But I am getting v.dataname as undefined.
You should be using the following attribute to access it:
v.dataset
Also, the data attributes should have a hyphen in them. Like data-name and not dataname.
So HTML would be:
<input type="text" class="fulltextbox saving_field" data-id="1" data-name="temperature" data-unit="° F" ng-model="addVt.Temp.value" />
And in Javascript:
tData.push({id: v.dataset.id, name: v.dataset.name, value: v.value, unit: v.dataset.unit});
See the documentation on how to properly use data attributes.
Related
I was working on a project using Angular 12. At some stage, I needed to render an array of objects which I got from the API. In each object, I have some fields of numbers like CostPrice, TradePrice, MRP, SellingPrice.
My target is to render those and view those inside the input tag. I have a variable named forViewDetails, based on which I was trying to make the field read-only. Inside the value attribute, I have binded the fields using attribute binding. There I was rendering the prices based on the forViewDetails option. If it is true then the values will appear with two decimal points. That's why I have used the number pipe inside a bracket. Else it will appear without points.
But the thing is it's working for CostPrice and TradePrice. But for MRP and TradePrice it's not working. If I remove the pipe from them, then it works. But after adding pipe the fields become empty. I thought maybe I am not getting the number in those fields. But I checked those, those were numbers.
I am attaching the code samples below. Any solution or suggestion is highly appreciated.
The output I am getting using pipe:
The output after removing the pipe from MRP:
<!-- trade price -->
<td style="width: 100px">
<input
[readonly]="forViewDetails"
id="itemTp_{{ i }}"
type="number"
min="0"
class="form-control w-100"
[value]="forViewDetails ? (item.TradePrice | number : '1.2-2') : item.TradePrice"
(input)="tpChanged(i, item, $event)"
(keyup.enter)="nextInput('tp', $event)"
[ngClass]="{ 'is-invalid': submitted && item.TradePrice == 0 }" />
</td>
<!-- mrp -->
<td style="width: 100px">
<input
[readonly]="forViewDetails"
id="itemMrp_{{ i }}"
type="number"
min="0"
class="form-control w-100"
[value]="forViewDetails ? (item.MRP | number : '1.2-2') : item.MRP"
(input)="mrpChanged(i, item, $event)"
(keyup.enter)="nextInput('mrp', $event)"
[ngClass]="{ 'is-invalid': submitted && item.MRP == 0 }" />
</td>
//object I am getting
{
Barcode: "B-090807",
BrandId: "BRD00002",
CategoryId: "SUBCAT0100",
CompanyId: "COM00002",
CostPrice: 900,
Discount: 0,
ExpDate: "2050-05-14",
Id: 8,
MRP: 1200,
MinShelfLife: 9999,
PVAT: 0,
ProductGrossWeight: 0,
ProductId: "PRD1671704018388",
ProductMargin: 0,
ProductName: "Hilsha Fish",
ProductNetWeight: 0,
ProductQty: 50,
ProductUnit: "kg",
SellingPrice: 1200,
StockReceivedId: "SR-1672203680930",
SupplierId: "SUP00002",
TAX: 0,
TradePrice: 900,
VAT: 0,
}
My target is to achieve all values in decimal form with two fraction points after it as I am getting in CostPrice and TradePrice.
The reason why it is not showing is due to the MRP value exceeding a thousand, with the Number pipe will display as "1,000.00" (with thousand separator), and the <input type="number" /> doesn't allow for the comma character.
In order to solve it, you should do either of these:
Not apply the number pipe to format the value in <input type="number" />
Implement a custom pipe to remove the comma character.
<input
[value]="forViewDetails ? (item.MRP | number: '1.2-2' | noComma) : item.MRP"
/>
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({ name: 'noComma' })
export class NoCommaPipe implements PipeTransform {
transform(value: any, ...args: any[]) {
return value.toString().replace(/,/g, '');
}
}
Demo # StackBlitz
Use <input type="text" /> instead to allow displaying the formatted number with thousand separator.
I have a list of input fields that are generated with a model. I am trying to add validation to them.
The requirement is they should not be empty or less than 2 characters.
problem is in the documentation only shows validation with non-dynamically generated variable Name. My fields are all generated dynamically. So there is no tempVariableName I can hardcode (otherwise they conflict), so I created temp variable from the name of the property I binded the field to. So I came up with something like this :
<div *ngFor="let field of connector.configFields">
<label>{{field.name}}</label>
<input [(ngModel)]="field.value" [type]="field.name === 'Password' ? 'password' : 'text'"
placeholder="{{field.name}} (required)"
ngControl="[fieldName+field.name]"
required minlength="2"
#fieldName+[field.name]="ngModel" />
<div *ngIf="(fieldName+[field.name]).errors && ((fieldName+[field.name]).dirty || (fieldName+[field.name]).touched)">
<span *ngIf="(fieldName+[field.name]).errors.required">Enter Name</span>
<span *ngIf="(fieldName+[field.name]).errors.minlength">Name minimum at 2 characters</span>
</div>
</div>
and the configFields in typescript look like this :
export class FieldModel {
public name: string;
public type: string;
public value: any;
}
But this simply would not work. I am new to angular 2 so I am not exactly sure what I did wrong.
You can use the unique index for each field in the array. Use this together with the name attribute (and ngModel) which will evaluate each form controls separately. So each input field gets the unique name, eg:
name="f{{i}}"
where we get {{i}} from the iteration:
<div *ngFor="let field of connector.configFields; let i = index">
So finally, your template could look like this:
<form #myForm="ngForm">
<div *ngFor="let field of connector.configFields; let i = index">
<input name="f{{i}}" [(ngModel)]="field.value" [type]="field.name === 'Password' ? 'password' : 'text'" required #f="ngModel" minlength="2"/>
<div *ngIf="f.errors && (f.dirty || f.touched)">
<div *ngIf="f.errors.required"> This field is required </div>
<div *ngIf="f.errors.minlength"> Min 2 chars </div>
</div>
</div>
</form>
Here's a live
Demo
Prepare data in model and return to angular. Angular and hard logic in the template = bad friends.
But if you have a select option and if has *ngFor for option then error message loses its mapping, due second *ngFor loop
better to define custom class for error message and use css display: none or **block*
.custom-valid-box{
display: none;
}
.form-control-danger + .custom-valid-box{
display: block;
}
Using the MvcForm HtmlHelper, I have added 'id' and 'data-values' attributes to a form in an ASP.NET MVC Razor view.
I created a new object 'DataVars' to hold local and Model values. Then I converted 'DataVars' object into a JSON object and added it to the form tag 'data-values' attribute to be referenced later by JavaScript on the client-side.
#{
var DataVars = new
{
var1= LocalVar,
var2= Model.var1
};
var testing = Json.Encode(DataVars);
}
#using (Html.BeginRouteForm("GetForm", FormMethod.Get, new
{
id = "formId",
data_values = #Html.Raw(testing)
})) {
<div class="form-element-group">
<label class="screen-reader-only" for="terms">#T("Tooltip")</label>
<input type="text" class="text" id="terms" autocomplete="off" name="q" placeholder="#T("Tooltip")" />
<span class="input-group-btn">
<input type="submit" class="button" value="#T("Button")" />
</span>
</div>
}
This all works, but the problem is, in the resulting HTML output in the form 'data-values' attribute, double quotes are encoded within the JSON object;
data-values="{"var1":"text info","var2":0}"
When stepping through the code in debug the value for variable testing is set to:
{\"var1\":\"text info\",\"var2\":0}
Is there a way to force the JSON to be;
data-values="{"var1":"text info","var2":0}"
Submitting a class roster. Adding 3 students at once. Each student has first, last, age.
Question: How can we get all of the students in an array of arrays?
students[0] => Array (
["first"] => "first name for 0",
["last"] => "last name for 0",
["age"] => "age for 0"
),
students[1] => Array (
["first"] => "first name for 1",
["last"] => "last name for 1",
["age"] => "age for 1"
),
...
Details
For one student:
<input type="text" name="first">
<input type="text" name="last">
<input type="text" name="age">
We can return multiple students in separate arrays like this:
<input type="text" name="students[first][]">
<input type="text" name="students[last][]">
<input type="text" name="students[age][]">
which returns an array of firsts, lasts and ages
students["first"] = [array of first names]
students["last"] = [array of last names]
students["age"] = [array of ages]
Theoretically we can get all the info for a student by accessing the same index (say "3" for each array).
We do not want to programatically add an index in the form.
Do not want:
<input type="text" name="students[hardcoded_index][first]">
<input type="text" name="students[hardcoded_index][last]">
<input type="text" name="students[hardcoded_index][age]">
If for any reason it matters, we are using Rails for views but can use form helpers or HTML.
tl;dr: Add empty brackets ([]) after students to the input names.
Fiddling with Rack::Utils.parse_nested_query it seems you can get the payload you want like this:
<!-- first student -->
<input type="text" name="students[][first]">
<input type="text" name="students[][last]">
<input type="text" name="students[][age]">
<!-- second student -->
<input type="text" name="students[][first]">
<input type="text" name="students[][last]">
<input type="text" name="students[][age]">
Note the empty brackets ([]) after students. This tells Rack you want the students param to be an array. Subsequent params encountered (with the same name) will start a new element.
POST /myroute?students[][first]=foo&students[][last]=bar&students[][age]=21&students[][first]=baz&students[][last]=qux&students[][age]=19
Gets parsed like this:
{"students" => [
{
"first" => "foo",
"last" => "bar",
"age" => "21"
},
{
"first" => "baz",
"last" => "qux",
"age" => "19"
}
]}
Further reading: http://codefol.io/posts/How-Does-Rack-Parse-Query-Params-With-parse-nested-query
I know the question is old , but I would like to add my experiences
also for future readers.
For those of you who want to process the data in a PHP enviroment ,
#messanjah's method won't work ,
The methods for parsing data like the built-in serializeArray or serialize are not parsing it as expected either.
This is what I tried so far ...
students[name]
students[][name] - Very Strange since it was meant to automatically index the array
students[name][]
Neither of them worked, but this students[<hardcoded-index>][name] worked for PHP ,
I know that although the question is against this method , but it
will be useful for PHP users who will land here in the nearby future
as the asker needed it for Ruby On Rails.
The method you choose to hard code the indexes is upto you , you can use a cleaner method by using javascript or you can manually hard code them initially in your form element.
Cheers
Please check this link is not working, i have no idea what is wrong in my code.
I am trying to create a blog application, which have title, description and comments, but i am not getting proper output.
<h4>Title</h4>
<label data-bind="value: title" />
<h4>Description</h4>
<label data-bind="value: description" />
<h4>Comments</h4>
<p data-bind="foreach: comments">
<label data-bind="value: commenter" /><br>
<label data-bind="value: comment" /><br>
</p>
var data = {"title": "blog1",
"description": "Description1",
"comments": [{"commenter": "commenter1", "comment": "comment1"},
{"commenter": "commenter2", "comment": "comment2"},
{"commenter": "commenter3", "comment": "comment3"},
{"commenter": "commenter4", "comment": "comment4"}]};
function Comment(data) {
this.commenter = ko.observable(data.commenter);
this.comment = ko.observable(data.comment);
}
function BlogViewModel(data) {
var self = data;
self.title = data.title;
self.description = data.description;
self.comments = ko.observableArray(ko.utils.arrayMap(data.comments, function (com) {
return new Comment(com.commenter, com.comment);
}));
}
ko.applyBindings(new BlogViewModel(data));
You have multiple problems with your code some are related to KnockOut some of them are not:
Which are not related to KO:
In BlogViewModel the self variable should hold this not the data parameter: so it should be var self = this;
Your comment mapping is wrong: the new Comment(com.commenter, com.comment) should be new Comment(com)
Which are related to KO:
The value binding is used for input elements, you have labels so you need to use the text binding instead. E.g data-bind="text: title"
KO needs valid html. Because the self-closing label tag is not valid you need to add the closing tags to your labels e.g <label data-bind="text: description"></label>
Here is a working JSFiddle containg all the fixes.