How to display complex object attributes in form fields in angular - json

I have a JSON object with the structure below which I want to display in a form for edit when I clicked on edit button on my table row.
json
{
"id": 123,
"name": "Paul",
"cars": [
{
"type": "toyota",
"year": "2013"
},
{
"type": "audi",
"year": "2010"
}
]
}
I need help on how to display the type of each cars object in my table file separated by comma(,). I got the object id and name displayed but not attributes in the cars array. How do I complete my .ts code so that the type of each car could show up in my table.
.ts
showRowDetail( data: any ) {
this.formData.controls.id.setValue( data.id );
this.formData.controls.name.setValue( data.name );
//how do I update here to set the cars: types
}
.html
<div class="form-group">
<label>ID:</label> <input type="text" class="form-control"
formControlName="id">
</div>
<div class="form-group">
<label>Name:</label><input type="text" class="form-control"
formControlName="name">
</div>
<div class="form-group">
<label>Cars:</label> <input type="text" class="form-control"
formControlName="cars">
</div>
I omitted the *ngFor table code, the showRowDetail function is used on the edit button, which when clicked it opens a modal that present the form where the object data are shown. data.id and data.name fields are working, just the cars type I needed help with.

how to display the "type" of each "cars" object in my table file
seperated by comma(,)
Generate comma separated type values from carsarray using map() and join().
showRowDetail( data: any ) {
this.formData.controls.id.setValue( data.id );
this.formData.controls.name.setValue( data.name );
let types = data.cars.map(car => car.type).join(", ");
this.formData.controls.cars.setValue(types);
}

Related

Saving and displaying "nested" JSON data from API

I have the following format of JSON data fetched from an API and stored in IntentList
{
"id": 22,
"name": "IntentName",
"fk_app": 3,
"fk_intent": null,
"nlu_models": [],
"sentences": [
{
"text": "text1",
"id": 2308
},
{
"text": "text2",
"id": 2309
},......
So there are these levels : the first having "name" and "sentences", and the second which is inside sentences, having "text".
My goal is to be able to search the API data By text and to display on each row the name and text found inside the sentences related to that text.
Therefore if I search "text" this would appear => IntentName text1 IntentName text2
if I search text1 this would appear => IntentName text1
-----What I have done/tried so far-----
I searched for corresponding text and stored its intent object and was only able to display its intent name
Typescript:
fetchIntentsTxt(event: any) {
if (event.target.value === '') {
return this.searchResultINTxt = [];
}
this.searchResultINTxt = this.IntentList.filter(
i => i.sentences.some(
s => s.text.toLowerCase().includes(event.target.value.toLowerCase())));
}
Html:
<input type="text" autocomplete="off" [(ngModel)]="searchInputINTxt" (keyup)="fetchIntentsTxt($event)"
class="form-control" id="search0" placeholder="Search for Intents by Text">
<a #myIntentTxt *ngFor="let intentTxt of searchResultINTxt" >{{intentTxt.sentences.text(this doesn't work obviously)}}<span
class="float-right">{{intentTxt.name}}</span> <br></a>
Any recommendation is appreciated, even if it meant changing the search function. Thanks in advance.
Example: https://stackblitz.com/edit/angular-ivy-pyaq7a
I would just create a new array in the fetchIntentsTxt method and add the data I want to display by the user input/search. After "filtering" all the data I need I set it to the variable thats iterated over in the View/Template.
public fetchIntentsTxt(searchValue: string): void {
const searchResults = [];
for (const entry of this.intentList) {
for (const sentence of entry.sentences) {
if (sentence.text.toLowerCase().includes(searchValue)) {
searchResults.push({
name: entry.name,
text: sentence.text,
});
}
}
}
this.searchResultINTxt = searchResults;
}
View:
<input type="text" autocomplete="off" [(ngModel)]="searchInputINTxt" (ngModelChange)="fetchIntentsTxt($event)" class="form-control" id="search0" name="search0" placeholder="Search for Intents by Text"/><br />
<a #myIntentTxt *ngFor="let intentTxt of searchResultINTxt">
{{ intentTxt.text }}<span class="float-right">{{ intentTxt.name }}</span>
<br/>
</a>
Also note here, I used the (ngModelChange) instead of the (keyup) on the search input so I do not need to hassle around with the events and just get the value I need for filtering.

Laravel complains for missing non-nullable value, but it is there

I have the following code in Laravel 5.4.* to store an array of JSON objects.
Sample::where('contest_id', $request->get('contest_id'))
->where('type', '0')
->delete();
if ( $request->get('extra3') ) {
$samples = $request->get('samples');
//return $samples;
Sample::insert($samples);
}
I had an error for a missing value that is not nullable, so I started the debugging.
This is the return of the $samples, just before the encoding:
[
{
"id": 16,
"contest_id": "35",
"product_id": "2",
"supplier_id": "2",
"quantity": "5",
"type": "0",
"created_at": null,
"updated_at": null
},
{
"contest_id": 35,
"type": "0",
"product_id": "4",
"supplier_id": "3",
"quantity": 3
}
]
However, if I commented out the return and let the eloquent runs, the insert is messed up.
This is the full error
{"error":{"message":"SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: samples.supplier_id (SQL: insert into \"samples\" (\"contest_id\", \"created_at\", \"id\", \"product_id\", \"quantity\", \"supplier_id\", \"type\", \"updated_at\") select 1 as \"contest_id\", as \"created_at\", 5 as \"id\", 2 as \"product_id\", 5 as \"quantity\", 2 as \"supplier_id\", 0 as \"type\", as \"updated_at\" union all select 1 as \"contest_id\", 1 as \"created_at\", 1 as \"id\", 1 as \"product_id\", 0 as \"quantity\", ? as \"supplier_id\", ? as \"type\", ? as \"updated_at\")","code":"23000","status_code":500}}
Edit: A few more details how I reproduce the error. I don't have it on every insert request, but only after a certain process.
I have a dynamic form with Angular where user can create as many models of Sample as she wants. The first time the user send the request with the models, Laravel saves those without an error.
When I refresh the page and the form is created automatically with the data that I had in the DB, if I remove one of them and create a new one, but keep at least one of the previous data, then I have the error.
Just before the above code, I have a line that delete data from the same table, so everything that was there, isn't during the insert command.
HTML of the dynamic form:
<div class="row col-md-12" *ngFor="let input of initSamples; let i=index">
<div class="col-md-4">
<label *ngIf="i==0" for="product{{i}}" class="col-md-12">Product</label>
<div class="input-group">
<select name="product{{i}}" [(ngModel)]="input.product_id" id="product{{i}}" class="form-control">
<option *ngFor="let product of products" value="{{product.id}}">{{product.name}}</option>
</select>
</div>
</div>
<div class="col-md-4">
<label *ngIf="i==0" for="supplier{{i}}" class="col-md-12">Supplier</label>
<div class="input-group">
<select name="supplier{{i}}" [(ngModel)]="input.supplier_id" id="supplier{{i}}" class="form-control ">
<option *ngFor="let supplier of suppliers" value="{{supplier.id}}">{{supplier.name}}</option>
</select>
</div>
</div>
<div class="col-md-2">
<label *ngIf="i==0" for="quantity{{i}}" class="col-md-12">Quantity</label>
<input type="number" min=1 step=1 [(ngModel)]="input.quantity" id="quantity{{i}}" name="quantity{{i}}" class="form-control">
</div>
</div>

HTML Form: POST an array of objects

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

How to parse form array in golang Beego

How to parse html form array with Beego.
<input name="names[]" type="text" />
<input name="names[]" type="text" />
<input name="names[]" type="text" />
Go Beego
type Rsvp struct {
Id int `form:"-"`
Names []string `form:"names[]"`
}
rsvp := Rsvp{}
if err := this.ParseForm(&rsvp); err != nil {
//handle error
}
input := this.Input()
fmt.Printf("%+v\n", input) // map[names[]:[name1 name2 name3]]
fmt.Printf("%+v\n", rsvp) // {Names:[]}
Why Beego ParseForm method return an empty names?
How to get values into rsvp.Names?
Thanks #ysqi for giving me a hint. I am adding a little detailed example to parse associate array like form data in beego
Here is my form structure:
<input name="contacts[0][email]" type="text" value="a1#gmail.com"/>
<input name="contacts[0][first_name]" type="text" value="f1"/>
<input name="contacts[0][last_name]" type="text" value="l1"/>
<input name="contacts[1][email]" type="text" value="a2#gmail.com"/>
<input name="contacts[1][first_name]" type="text" value="f2"/>
<input name="contacts[1][last_name]" type="text" value="l2"/>
golang(beego) code:
contacts := make([]map[string]string, 0, 3)
this.Ctx.Input.Bind(&contacts, "contacts")
contacts variable:
[
{
"email": "user2#gmail.com",
"first_name": "Sam",
"last_name": "Gamge"
},
{
"email": "user3#gmail.com",
"first_name": "john",
"last_name": "doe"
}
]
Now you can use it like:
for _, contact := range contacts {
contact["email"]
contact["first_name"]
contact["last_name"]
}
As you can see from the implementation of the FormValue method of the Request, it returns the first value in case of multiple ones:
http://golang.org/src/pkg/net/http/request.go?s=23078:23124#L795
It would be better to get the attribute itself r.Form[key] and iterate over all the results manually. I am not sure how Beego works, but just using the raw
Request.ParseForm and Request.Form or Request.PostForm maps should do the job.
http://golang.org/src/pkg/net/http/request.go?s=1939:6442#L61
You can do like this : see doc
v := make([]string, 0, 3)
this.Ctx.Input.Bind(&v, "names")

knockout template parsing of json data is not working

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.