meteor autoform string array shows empty field - arrays

I make edit form for some collection, it has Array fields 'phones', each element is String
When I trying to make afArrayField from this field it shows block with one empty string
Schema:
{phones:
{type: Array,
minCount: 1,
label: "Phones numbers"},
{"phones.$":
{type: String}
}
Template:
{{> afQuickField name="phones" value=phones}}
In object array 'phones' is presented

I've the following:
phones: {
type: [String],
minCount: 1,
label: "Phones numbers"
},
'phones.$': {
autoform: {
afFieldInput: {
type: 'text'
}
}
}
Template helper
Template.home.helpers({
doc: {phones: ['09988765', '0998776']} // this should come from db.findOne
})
In template:
{{#autoForm id='test' schema="Schema.Array" type="update" doc=doc}}
{{> afQuickField name="phones" value=doc.phones}}
{{/autoForm}}
I'm having this:
I've the following package dependencies:
meteor-platform
standard-app-packages
iron:router
iron:layout
aldeed:collection2
aldeed:simple-schema
aldeed:autoform
nemo64:bootstrap
less
accounts-base
accounts-password

Related

How to properly do nested schema with mongoose in React?

I have a Class schema that looks like this:
const ClassSchema = new mongoose.Schema({
title: {
type: String,
...
},
classImageURL: {
type: String,
...
},
imageWidth: {
type: String,
...
},
imageHeight: {
type: String,
...
}
});
module.exports = mongoose.models.Class || mongoose.model("Class", ClassSchema);
And a Subject schema that looks like this:
const SubjectSchema = new mongoose.Schema({
subjectTitle: {
type: String,
...
},
subjectImageURL: {
type: String,
...
},
imageWidth: {
type: String,
...
},
imageHeight: {
type: String,
...
},
});
module.exports =
mongoose.models.Subject || mongoose.model("Subject", SubjectSchema);
On a dynamic page named [className], I am getting the data of the particular className from the database and destructured it. Now, on the class page, I want to send a post request to the database using all the fields titled in the Subject schema. But, I also want to add the class data that I got and add it to the Subject schema.
I used a state to hold all the data:
setForm({
subjectTitle: enteredSubjectTitle,
subjectImageURL: response.data.url,
imageWidth: response.data.width,
imageHeight: response.data.height,
classDetail: classDetail // this is the data I have on the particular class data
}); // I want to add
And I tried to make changes in the Subject schema like this:
classDetail: { Class }, // I added this in the last part of the schema
It results in a post error.
How can I achieve what I want to?

How to build a dynamic object in Angular

Hello I have the following problem, I want to form the following payload structure that is in the example of the first code paragraph, I was advancing well until I came across the part of the form that is dynamic and no matter how hard I try it has not worked out, I would appreciate it really much your help.
The problem is that I cannot build the structure as the first paragraph of code, especially in the dataCollege field, since it does not save the array dynamically.
I tried to put the FormControl in the html where I render the dynamic inputs but it gives me an error
This is the structure of the payload that I was able to assemble the first 3, but the last one is where I have a problem, which is the field datosCole, which is dynamic, depending on the GradosCole field, which can be initial, has 2 values, primary has 3 values and secondary has 4 values
{ name: Sara,
age: 14,
gradeCollege: Secondary,
dataCollege: {
course: "Maths",
schedule: "Afternoon",
section: "A",
teacher: "Mateo",
}
}
This is my HTML sheet of how I build my form.
<div>
<form [formGroup]="form">
<!-- Name -->
<mat-form-field>
<input matInput type="text" placeholder="Name" [formControl]="name">
</mat-form-field>
<!-- Age -->
<mat-form-field>
<input matInput type="text" placeholder="Age" [formControl]="age">
</mat-form-field>
<!-- Grade -->
<mat-form-field>
<mat-label>Grade</mat-label>
<mat-select [formControl]="gradeCollege">
<mat-option *ngFor="let item of grades" [value]="item" (click)="getData(item)">
{{item}}
</mat-option>
</mat-select>
</mat-form-field>
<!-- dynamic data -->
<div *ngFor="let item of data; index as i" >
<mat-form-field>
<input matInput [type]="item.type" [placeholder]="item.label" [formControl]="dataCollege" >
</mat-form-field>
</div>
</form>
<div>
<button type="button" (click)="save()">Save</button>
</div>
</div>
This is my TS file
import { Component, OnInit } from '#angular/core'; import { FormGroup, FormBuilder, Validators, AbstractControl } from '#angular/forms';
#Component({ selector: 'app-datos', templateUrl: './datos.component.html', styleUrls: ['./datos.component.scss'] }) export class DatosComponent implements OnInit {
public grades: any[] = ['initial','primary','secondary'];
public data: any[] = []
// Form
public form: FormGroup;
public name: AbstractControl;
public age: AbstractControl;
public gradeCollege: AbstractControl;
public dataCollege: AbstractControl;
constructor( protected fb: FormBuilder, ) {
}
ngOnInit() {
this.form = this.fb.group({
name: ['', Validators.compose([Validators.required])],
age: [''],
gradeCollege: ['', Validators.compose([Validators.required])],
dataCollege: ['']
});
this.name= this.form.get('name');
this.age = this.form.get('age');
this.gradeCollege = this.form.get('gradeCollege');
this.dataCollege = this.form.get('dataCollege'); }
getData (typeGrade: any) {
console.log(typeGrade);
if(typeGrade === 'initial'){
this.data = null
this.data = [
{type: 'text', label: 'course'},
{type: 'text', label: 'schedule'},
]
}
if(typeGrade === 'primary'){
this.data = null
this.data = [
{type: 'text', label: 'course'},
{type: 'text', label: 'schedule'},
{type: 'text', label: 'section'}
]
}
if(typeGrade === 'secondary'){
this.data= null
this.data = [
{type: 'text', label: 'course'},
{type: 'text', label: 'schedule'},
{type: 'text', label: 'section'},
{type: 'text', label: 'teacher'}
]
}
}
submit() {
const payload = {
name: this.name.value,
age: this.age.value,
gradeCollege: this.gradeCollege.value,
dataCollege: this.dataCollege.value,
};
console.log(payload)
}}
this is the error
ERROR TypeError: ctx.save is not a function
at ActionDialogComponent_Template_button_click_13_listener (template.html:34:36)
at executeListenerWithErrorHandling (core.js:21860:1)
at wrapListenerIn_markDirtyAndPreventDefault (core.js:21902:1)
at HTMLButtonElement. (platform-browser.js:976:1)
at ZoneDelegate.invokeTask (zone-evergreen.js:399:1)
at Object.onInvokeTask (core.js:41686:1)
at ZoneDelegate.invokeTask (zone-evergreen.js:398:1)
at Zone.runTask (zone-evergreen.js:167:1)
at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:480:1)
at invokeTask (zone-evergreen.js:1621:1)
defaultErrorLogger # core.js:6241
handleError # core.js:6294
handleError # core.js:13881
executeListenerWithErrorHandling # core.js:21863
wrapListenerIn_markDirtyAndPreventDefault # core.js:21902
(anonymous) # platform-browser.js:976
invokeTask # zone-evergreen.js:399
onInvokeTask # core.js:41686
invokeTask # zone-evergreen.js:398
runTask # zone-evergreen.js:167
invokeTask # zone-evergreen.js:480
invokeTask # zone-evergreen.js:1621
globalZoneAwareCallback # zone-evergreen.js:1647
I imagine that you want that the "dataCollege" is an Array, not an object.
Some like, e.g.
{ name: Sara,
age: 14,
gradeCollege: Secondary,
dataCollege:[{
course: "Maths",
schedule: "Afternoon",
section: "A",
teacher: "Mateo",
}
]
}
or if you has two elements
{ name: Sara,
age: 14,
gradeCollege: Secondary,
dataCollege:[{
course: "Maths",
schedule: "Afternoon",
section: "A",
teacher: "Mateo",
},
{
course: "Language",
schedule: "Afternoon",
section: "C",
teacher: "Alex",
}
]
}
Well you has an array of objects, so you should use an FormArray of FormGroups
A FormArray of FormGroup as mannage always in the same way
1.-Declare in a .ts a getter of your formArray
get dataCollege()
{
return this.form.get('dataCollege') as FormArray
}
2.- in .html
<form [formGroup]="form">
...inputs thats belog to the main form in the way,e.g...
..see that you use formControlName="control-name"
..the control-name between quotes but the "formControlName" as is..
<input formControlName="name">
....
..a div with formArrayName..
<div formArrayName="dataCollege">
..a ngFor to iterate over the formArray.controls..
..you use the "getter" defined in the fisrt step..
..you add [formGroupName]="i"..
<div *ngFor="let group of dataCollege.controls;let i=index"
[formGroupName]="i"
..like in the main group you use formControlName for the...
..controls of the FormArray...,e.g.
<input formControlName="course">
</div>
</div>
And forget all your getters to get the control

how to do ngFor inside ngFor dynamically in angular 8?

Hi what i trying to achieve is ngFor with dynamic value inside ngFor, is this possible? i try using ngModel inside it too and it didn't work out. Here is what i do :
inside my home.component.ts :
import { Component, OnInit } from '#angular/core';
import {CdkDragDrop, moveItemInArray} from '#angular/cdk/drag-drop';
export interface Condition {
value: string;
viewValue: string;
}
export interface ListProduk {
value: string;
viewValue: string;
}
export interface DragBox {
value: string;
viewValue: string;
}
export interface ListModel {
value: string;
viewValue: string;
single_item: string;
}
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
conditions: Condition[] = [
{ value: 'if', viewValue: 'IF' },
{ value: 'else', viewValue: 'ELSE' },
{ value: 'then', viewValue: 'THEN' },
{ value: 'if else', viewValue: 'IF ELSE' },
{ value: 'or', viewValue: 'OR' },
{ value: 'and', viewValue: 'AND' }
];
listProduks: ListProduk[] = [
{ value: 'mcm-508', viewValue: 'MCM-508' },
{ value: 'bl-100 pl', viewValue: 'BL-100 PL' },
{ value: 'bl-150 bl', viewValue: 'BL-150 BR' },
{ value: 'bl-302gs', viewValue: 'BL-302GS' },
{ value: 'bl-52gl', viewValue: 'BL-52GL' }
];
listModels: ListModel[] = [
{ value: 'conditions', viewValue: 'Condition', single_item:'condition' },
{ value: 'listProduks', viewValue: 'List Produk', single_item:'listProduk' },
]
constructor() { }
ngOnInit() {
}
drop(event: CdkDragDrop<string[]>) {
moveItemInArray(this.listModels, event.previousIndex, event.currentIndex);
}
}
and then here is my home.component.html :
<p>home works!</p>
<div cdkDropList cdkDropListOrientation="horizontal" class="example-list" (cdkDropListDropped)="drop($event)">
<div class="example-box" *ngFor="let listModel of listModels" cdkDrag>
<mat-form-field>
<mat-label>Pick {{listModel.value}} :</mat-label>
<mat-select>
<mat-option *ngFor="let {{listModel.single_item}} of {{listModel.value}}" [value]="{{listModel.single_item}}.value">
test
</mat-option>
</mat-select>
</mat-form-field>
<div>
<i class="material-icons">
arrow_right_alt
</i>
</div>
</div>
</div>
i try to do loop the mat-select dynamically, since i want it loop an array that have different name, i need value in listModel array to print to *ngFor inside mat-select. Which is this line :
<mat-option *ngFor="let {{listModel.single_item}} of {{listModel.value}}" [value]="{{listModel.single_item}}.value">
test
</mat-option>
how to do this properly?
UPDATED QUESTION After update my code with Ahmed comment, which is my Html is looked like this :
<p>home works!</p>
<div cdkDropList cdkDropListOrientation="horizontal" class="example-list" (cdkDropListDropped)="drop($event)">
<div class="example-box" *ngFor="let listModel of listModels" cdkDrag>
<mat-form-field>
<mat-label>Pick {{listModel.value}} :</mat-label>
<mat-select>
<mat-option *ngFor="let a of listModel.value" [value]="a.value">
{{a.viewValue}}
</mat-option>
</mat-select>
</mat-form-field>
<div>
<i class="material-icons">
arrow_right_alt
</i>
</div>
</div>
</div>
and this give me an error like this :
ERROR Error: Cannot find a differ supporting object 'conditions' of
type 'string'. NgFor only supports binding to Iterables such as
Arrays.
what did i missed?
You can display this using a function, which would return the correct array. We are calling this in the template. BE CAREFUL, I would never recommend calling a function in template, if it is just all possible. This can seriously hurt performance in an app. But if you don't have much content on this page, it is pretty safe to use. So I would suggest the following:
<div *ngFor="let value of getList(listModel.value)">
and the function would return the correct array:
getList(value) {
return this[value]
}
You could also make a slight change to the model and pass an optional parameter with the array with the correct array to the object itself. You can do this in OnInit:
ngOnInit() {
this.listModels.forEach(x => {
x.customArray = this[x.value]
})
}
and use it like normal iteration in *ngFor:
<div *ngFor="let value of listModel.customArray">
Here's a STACKBLITZ with both options

Mongoose Schema. How to create default value for a object of object?

Meet my UserModel:
var UserModel = mongoose.model('UserModel',
{
username: { type: String, default: 'Nameless'},
password: String,
registry: String,
});
I want to do something like this to my username key:
username: {
description: {type: String, default: 'Name'},
value: {type: String, default: 'Nameless'}
};
My goal is to use this keys in a ng-repeat, so I can do something like this:
<p> {{ user.username.desc }}: {{ user.username.value }} </p>
With output: Name: Nameless
My problem is: I should be doing something wrong. I'm receiving syntax errors and my server dont even start.
:)
You can set default with a function, so create one, also you can use preSave to validate your model like:
UserModel.pre('save', function(next) {
var self = this;
// validate username field here
});
}
more info here http://mongoosejs.com/docs/middleware.html

NgRepeat filtering complex structure

I have been given a complex JSON object to display inside Angular and I'd like to filter it into two lists after having drilled down into the object.
The object structure is:
{
foo:
{
bar:
{
showA: { value: true, type: 'A' },
showB: { value: false, type: 'A' },
showC: { value: true, type: 'A' }
}
}
}
And I'm trying to achieve a list of "false" and "true".
In this case:
Disabled:
showB - Type: A
Enabled:
showA - Type: A
showC - Type: A
I can't filter the object and also can't obtain the "key" of the objects, e.g. "showA".
My attempt of using:
item in profile['foo']['bar'] | filter: { value: false }
Accesses the correct objects but I can't filter or get the "key" of it.
Here is a broken plunkr to demonstrate:
http://plnkr.co/edit/9NniQdo213AuEbf0pghA?p=preview
Any advice would be great!
Check out this working punkr: http://plnkr.co/edit/TdM9P592OXd6Bx81Bmbt?p=preview
It uses a custom filter, myFilter, which makes the filtering task pretty simple. myFilter returns a new object with only the objects having value equal to the value given as second argument to the filter.
app.filter('myFilter', function() {
return function(bar, value) {
var r = {};
for (var key in bar) {
if (bar[key].value == value) {
r[key] = bar[key];
}
}
return r;
}
});
To get the key with ng-repeat, use the following syntax:
<li ng-repeat="(key, item) in profile['foo']['bar'] | myFilter:false">
<input type="checkbox" ng-model="item.value" /> {{ key }}
</li>
If you can alter the structure of $scope.profile, the filtering task would be easier with this structure:
bar: [
{name: 'ShowA', value: false, type: 'A'},
...
]

Resources