In my angular5 application I have this form:
this.form = this.formBuilder.group({
institution: ['', [Validators.required, Validators.minLength(2)]],
color: [''],
...
addressesWithProducts: this.formBuilder.array([])
});
In order to add a new addressWithProducts I use this method:
addAddress() {
let addressWithProducts = this.formBuilder.group({
address: this.formBuilder.group({
...
country: ['', [Validators.minLength(2)]],
provinceType: ['', [Validators.minLength(2)]],
provinceTypesOfAddressWithProducts: [['test1', 'test2', 'test3']],
...
})
});
let addressesWithProducts: FormArray =
this.form.controls['addressesWithProducts'] as FormArray;
addressesWithProducts.push(addressWithProducts);
}
I will show test1, test2 and test3 with:
<form [formGroup]="form" (ngSubmit)="onSubmit()">
...
<div formArrayName="addressesWithProducts">
<mat-form-field style="width:95%">
<mat-select placeholder="District" formArrayName="provinceTypesOfAddressWithProducts">
<mat-option *ngFor="let provinceType of provinceTypesOfAddressWithProducts" [value]="provinceType">
{{provinceType | translate}}
</mat-option>
</mat-select>
</mat-form-field>
but no values are shown in select. Does anyone have any hint in order to get it work?
Related
I'm getting this error:
ERROR Error: formControlName must be used with a parent formGroup directive. You'll want to add a formGroup directive and pass it an existing FormGroup instance (you can create one in your class).
I have already import import { ReactiveFormsModule } from '#angular/forms'; in module.ts
this is the template .html:
<mat-step [stepControl]="bankFormGroup" label="Some label">
<form [formGroup]="bankFormGroup">
<mat-form-field>
<mat-label>Banco</mat-label>
<mat-select ngDefaultControl formControlName="bank">
<mat-option *ngFor="let bank of banks" value="{{bank.id}}">
{{bank.id}} - {{bank.name}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>Agência</mat-label>
<input matInput formControlName="agency" placeholder="0001">
</mat-form-field>
<mat-form-field>
<mat-label>Número da Conta Corrente</mat-label>
<input matInput formControlName="account" placeholder="26262661">
</mat-form-field>
{...action form}
</form>
</mat-step>
this is the component.ts:
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
export class UploadComponent {
bankFormGroup: FormGroup = this._formBuilder.group({
bank: ['', Validators.required],
agency: ['', Validators.required],
account: ['', Validators.required]
});
banks: any[] = [
{ id: '001', name: 'Banco do Brasil S.A.' },
{ id: '237', name: 'Banco Bradesco S.A.' },
];
constructor(private _formBuilder: FormBuilder) { }
}
I've already see another issues similar in another pages, like https://stackoverflow.com/questions/43305975 . But still i'm not able to remove this issue.
i'm using:
"#angular/forms": "^11.0.0",
"#angular/core": "^11.0.0",
"#angular/material": "^11.0.3",
The error was in another form in same component. Another form without <form [formGroup]="FormGroupName"> parent..
Check if there is another form without a parent container with [formGroup]
For some reason my select to cannot get access to the id value I have setup a few counties as such I am using the https://select2.org/ dropdown to be able to show images of countries
<script>
$(function () {
//Initialize Select2 Elements
$('.select2').select2()
var isoCountries = [
{ id: 1, flag: 'af', text: 'Afghanistan' },
{ id: 2, flag: 'ax', text: 'Aland Islands' },
{ id: 3, flag: 'al', text: 'Albania' },
{ id: 4, flag: 'dz', text: 'Algeria' },
{ id: 5, flag: 'as', text: 'American Samoa' },
{ id: 6, flag: 'ad', text: 'Andorra' },
{ id: 7, flag: 'ao', text: 'Angola' },
];
function formatCountry(country) {
if (!country.id) { return country.text; }
var $country = $(
'<span class="flag-icon flag-icon-' + country.id.toLowerCase() + ' flag-icon-squared"></span>' +
'<span class="flag-text">' + country.text + "</span>"
);
return $country;
};
//Assuming you have a select element with name country
// e.g. <select name="name"></select>
$("[name='Flag']").select2({
placeholder: "Please Select a country",
templateResult: formatCountry,
data: isoCountries
});
<script>
When I look at the generated content for the drop down select for which is produced as such.
<div class="form-group">
#Html.LabelFor(m => m.CountryOfBirth)
<span asp-validation-for="CountryOfBirth" class="text-danger"></span>
<select asp-for="CountryOfBirth" name="CountryOfBirth" id="CountryOfBirth" class="form-control select2" style="height:35px" name="Flag">
<option>Please select Country Of Birth</option>
</select>
<span asp-validation-for="CountryOfBirth" class="text-danger"></span>
</div>
And generated as such no where in the html is the id for the selected item so how would the controller be able to bind it
<span class="selection"><span class="select2-selection select2-selection--single" role="combobox" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-disabled="false" aria-labelledby="select2-CountryOfBirth-container">
<span class="select2-selection__rendered" id="select2-CountryOfBirth-container" role="textbox" aria-readonly="true" title="United Kingdom">United Kingdom</span>
<span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span></span>
<select asp-for="CountryOfBirth" name="CountryOfBirth" id="CountryOfBirth" class="form-control select2" style="height:35px" name="Flag">
From the codes above, you set name attributes for the select tag three times.
asp-for="CountryOfBirth"
name="CountryOfBirth"
name="Flag"
Just keep asp-for and delete others. asp-for attribute extracts the name of the specified model property into the rendered HTML.
Codes of view
<div class="form-group">
#Html.LabelFor(m => m.CountryOfBirth)
<span asp-validation-for="CountryOfBirth" class="text-danger"></span>
<select asp-for="CountryOfBirth" class="form-control select2" style="height:35px">
<option>Please select Country Of Birth</option>
</select>
<span asp-validation-for="CountryOfBirth" class="text-danger"></span>
</div>
Codes of JS
<script>
$(function () {
//Initialize Select2 Elements
//$('.select2').select2();
var isoCountries = [
{ id: 1, flag: 'af', text: 'Afghanistan' },
{ id: 2, flag: 'ax', text: 'Aland Islands' },
{ id: 3, flag: 'al', text: 'Albania' },
{ id: 4, flag: 'dz', text: 'Algeria' },
{ id: 5, flag: 'as', text: 'American Samoa' },
{ id: 6, flag: 'ad', text: 'Andorra' },
{ id: 7, flag: 'ao', text: 'Angola' },
];
function formatCountry(country) {
if (!country.id) { return country.text; }
var $country = $(
'<span class="flag-icon flag-icon-' + country.flag + ' flag-icon-squared"></span>' +
'<span class="flag-text">' + country.text + "</span>"
);
return $country;
};
//Assuming you have a select element with name country
// e.g. <select name="name"></select>
$("[id='CountryOfBirth']").select2({
placeholder: "Please Select a country",
templateResult: formatCountry,
data: isoCountries
});
$('#CountryOfBirth').val(#Model.CountryOfBirth); //init option
$('#CountryOfBirth').trigger('change');
});
</script>
Test of result
I'am using angular-calendar with a custom template as given here : https://mattlewis92.github.io/angular-calendar/#/custom-templates,
For the month - view i would like to have a "Show more" option which will load more events in the day cell. By default i want to have only 4 events listed on the day cell. Something similar to google calendar.
Let me know how can if i have an option for this in the month view or if i manually need to populate only 4 events and have a show more icon in the array and on click load the remaining in (eventClicked).
Screenshot of the calendar i am trying:
I found the answer , by creating a custom template and using a EVENT_LIMIT which i have set to 4 , so by default i will have 4 events listed in month view , and if there are 3 more events , i would get the "3 More" in the month view.
More popup html :
<div class="more-popup scrollbar" *ngIf="moreEvents.length>0"
[ngStyle]="{'top' : moreEventStyles.top , 'left': moreEventStyles.left}">
<div class="header">
<button type="button" class="close close-more-popup" (click)="moreEvents=[]">×</button>
<div class="header-day">{{moreEvents[0].start | date : 'E'}}</div>
<div class="header-date">{{moreEvents[0].start | date : 'd'}} </div>
</div>
<div class="body">
<div *ngFor="let e of moreEvents">
<div class="body-events" [ngStyle]="{ backgroundColor: e.color?.primary }"
(click)="handleEvent('Clicked', e)">{{e.title}}</div>
</div>
</div>
</div>
<mwl-calendar-month-view *ngSwitchCase="CalendarView.Month" [viewDate]="viewDate"
[events]="calEvents" [cellTemplate]="customCellTemplate"
(eventClicked)="handleEvent(event, $event.event)"
(dayClicked)="dayClicked($event.day)">
</mwl-calendar-month-view>
<ng-template #customCellTemplate let-day="day" let-locale="locale"
let-tooltipPlacement="tooltipPlacement"
let-highlightDay="highlightDay" let-unhighlightDay="unhighlightDay"
let-eventClicked="eventClicked"
let-tooltipTemplate="tooltipTemplate"
let-tooltipAppendToBody="tooltipAppendToBody" let-tooltipDelay="tooltipDelay">
<div class="cal-cell-top">
<span class="cal-day-badge" *ngIf="day.badgeTotal > 0">
{{ day.badgeTotal }}</span>
<span class="cal-day-number">
{{ day.date | calendarDate:'monthViewDayNumber':locale }}</span>
</div>
<div *ngIf="day.events.length > 0">
<div *ngFor="let event of day.events; trackBy: trackByEventId; index as i">
<ng-template *ngIf="i < EVENT_LIMIT; then showEventsBlock; else showMoreBlock">
</ng-template>
<ng-template #showEventsBlock>
<div class="cal-events" *ngIf="i < EVENT_LIMIT" [ngStyle]="{ backgroundColor: event.color?.primary }"
[ngClass]="event?.cssClass" (mwlClick)="eventClicked.emit({event: event})" [mwlCalendarTooltip]="event.title | calendarEventTitle: 'monthTooltip':event"
[tooltipPlacement]="tooltipPlacement" [tooltipEvent]="event" [tooltipTemplate]="tooltipTemplate"
[tooltipAppendToBody]="tooltipAppendToBody" [tooltipDelay]="tooltipDelay">
{{event.title}}
</div>
</ng-template>
<ng-template #showMoreBlock>
<ng-container *ngIf="i === EVENT_LIMIT">
<div class="cal-events" (mwlClick)="handleMoreEvent($event,day.events)">
<a class="showmore"> {{day.events.length - EVENT_LIMIT}} more</a>
</div>
</ng-container>
</ng-template>
</div>
</div>
</ng-template>
ts:
handleMoreEvent(e: any , events: LogBookCalendarEvent[]) {
this.moreEvents = events;
this.moreEventStyles.top = `${e.srcElement.offsetTop}px`;
this.moreEventStyles.left = `${e.srcElement.offsetLeft}px`;
this.moreEventStyles = {...this.moreEventStyles};
}
Screen shot of the result :
On click of the 3 more :
It's a good idea, if you want to do it without popup you can do it like this:
using angular-calendar with a custom template as given here
ts:
import { Component, ChangeDetectionStrategy } from '#angular/core';
import { CalendarEvent } from 'angular-calendar';
import {
startOfDay,
addDays,
} from 'date-fns';
import { BehaviorSubject, Subject, interval } from 'rxjs';
#Component({
selector: 'mwl-demo-component',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: 'template.html'
})
export class DemoComponent {
view: string = 'month';
viewDate: Date = new Date();
events: CalendarEvent[] = [
{ start: new Date(), title: 'An event' },
{ start: new Date(), title: 'An event' },
{ start: new Date(), title: 'An event' },
{ start: new Date(), title: 'An event' },
{ start: new Date(), title: 'An event' },
{ start: new Date(), title: 'An event' },
{ start: new Date(), title: 'An event' },
{ start: addDays(startOfDay(new Date()), 1), title: 'different date' },
{ start: addDays(startOfDay(new Date()), 1), title: 'different date' },
{ start: addDays(startOfDay(new Date()), 1), title: 'different date' },
{ start: addDays(startOfDay(new Date()), 1), title: 'different date' },
{ start: addDays(startOfDay(new Date()), 1), title: 'different date' },
];
showMore = false;
showMoreDate = null;
showMoreClicked(date: Date){
this.showMoreDate = date;
this.showMore = ! this.showMore;
}
}
change html line of *ngfor to:
`*ngFor="let event of day.events | slice:0:(showMoreDate==day.date && showMore) ? undefined :3; trackBy: trackByEventId"`
change html span to:
`Show {{ day.events.length - 3 }} {{ (showMoreDate==day.date && showMore) ? 'less' : 'more' }} `
result
How to pass default value in md-autocomplete?
Image 1 : HTML code
Image 2 : JS code
Image 3 : Output
As you can see, I am not getting any default country as output. Is there any way to do that?
Assign yr SearchText the default value & selectedItem the object.
$scope.local ={
...
searchText : 'Default Value',
selectedItem : 'Default object'
...
}
I write small codepen with autocomplete and default value.
What you must do:
Init main model.
Define model field, used in autocomplete md-selected-item property.
Define callback for loading autocomplete items.
Before save main model extract id (or other field) from associated field.
Main error in your code here:
$scope.local = {
...
selectedItem: 1, // Must be object, but not integer
...
}
(function(A) {
"use strict";
var app = A.module('app', ['ngMaterial']);
function main(
$q,
$scope,
$timeout
) {
$timeout(function() {
$scope.user = {
firstname: "Maxim",
lastname: "Dunaevsky",
group: {
id: 1,
title: "Administrator"
}
};
}, 500);
$scope.loadGroups = function(filterText) {
var d = $q.defer(),
allItems = [{
id: 1,
title: 'Administrator'
}, {
id: 2,
title: 'Manager'
}, {
id: 3,
title: 'Moderator'
}, {
id: 4,
title: 'VIP-User'
}, {
id: 5,
title: 'Standard user'
}];
$timeout(function() {
var items = [];
A.forEach(allItems, function(item) {
if (item.title.indexOf(filterText) > -1) {
items.push(item);
}
});
d.resolve(items);
}, 1000);
return d.promise;
};
}
main.$inject = [
'$q',
'$scope',
'$timeout'
];
app.controller('Main', main);
}(this.angular));
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/0.11.0/angular-material.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular-aria.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular-animate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/0.11.0/angular-material.min.js"></script>
</head>
<body ng-app="app" flex layout="column" layout-margin ng-controller="Main">
<md-content layout="column" class="md-whiteframe-z1" layout-margin>
<md-toolbar>
<div class="md-toolbar-tools">
<h3>Form</h3>
</div>
</md-toolbar>
<md-content class="md-whiteframe-z1">
<div class="md-padding">
<md-input-container>
<label for="firstname">First name</label>
<input type="text" name="firstname" ng-model="user.firstname" />
</md-input-container>
<md-input-container>
<label for="lastname">Last name</label>
<input type="text" name="lastname" ng-model="user.lastname" />
</md-input-container>
<md-autocomplete md-selected-item="user.group" md-items="item in loadGroups(filterText)" md-item-text="item.title" md-search-text="filterText">
<md-item-template>{{ item.title }}</md-item-template>
<md-not-found>No items.</md-not-found>
</md-autocomplete>
</div>
</md-content>
</md-content>
<md-content class="md-whiteframe-z1" layout-margin>
<md-toolbar>
<div class="md-toolbar-tools">
<h3>Model as JSON</h3>
</div>
</md-toolbar>
<md-content class="md-padding">
<p>
{{ user | json }}
</p>
</md-content>
</md-content>
</body>
I know this is an old question, but some people may benefit from my solution. I struggled with the problem of the model for the auto-complete being asynchronous and having my autocompletes as part of an ng-repeat. Many of the solutions to this problem found on the web have only a single auto complete and static data.
My solution was to add another directive to the autocomplete with a watch on the variable that I want to set as default for the auto complete.
in my template:
<md-autocomplete initscope='{{quote["Scope"+i]}}' ng-repeat='i in [1,2,3,4,5,6,7,8]'
class='m-1'
md-selected-item="ScopeSelected"
md-clear-button="true"
md-dropdown-position="top"
md-search-text="pScopeSearch"
md-selected-item-change='selectPScope(item.label,i)'
md-items="item in scopePSearch(pScopeSearch,i)"
md-item-text="item.label"
placeholder="Plowing Scope {{i}}"
md-min-length="3"
md-menu-class="autocomplete-custom-template"
>
then in my module:
Details.directive('initscope', function () {
return function (scope, element, attrs) {
scope.$watch(function (){
return attrs.initscope;
}, function (value, oldValue) {
//console.log(attrs.initscope)
if(oldValue=="" && value!="" && !scope.initialized){
//console.log(attrs.initscope);
var item = {id:0, order:0,label:attrs.initscope?attrs.initscope:"" }
scope.ScopeSelected = item;
scope.initialized = true;
}
});
};
});
this checks for changes to the quote["Scope"+i] (because initially it would be null) and creates an initial selected item and sets the autocompletes' selected item to that object. Then it sets an initialized value to true so that this never happens again.
I used timeout to do this.
$timeout(function() {
$scope.local = {selectedItem : 1}
}, 2000);
Here is my plunker example: http://plnkr.co/edit/Tc9FRHAEoQlOqy7sk1Ae?p=preview
What I'm trying to do:
Bind the checkbox html from field04 in my data to the cell using cellTemplate and still have access to its ng-click function.
Code in app.js:
var app = angular.module('app', ['ui.grid', 'ngSanitize']);
app.controller('MainCtrl', ['$scope', '$log', function ($scope, $log, $sce) {
$scope.myViewModel = {
someProp:'abc',
showMe : function(){
alert(this.someProp);
}
};
$scope.gridOptions = {
};
$scope.gridOptions.columnDefs = [
{ name: 'field01', field: 'field01' },
{ name: 'field02', field: 'field02'},
{ name: 'field03', field: 'field03', cellTemplate: '<input type="checkbox" ng-model="row.entity.field03" ng-click="$event.stopPropagation();getExternalScopes().showMe()">'},
{ name: 'field04', field: 'field04', cellTemplate: 'viewTemplate2'},
{ name: 'field05', field: 'field05', cellTemplate: 'viewTemplate2'}
];
$scope.gridOptions.data = [
{
"field01": "one",
"field02": "01",
"field03": false,
"field04": '',
"field05": '',
},
{
"field01": "two",
"field02": "02",
"field03": false,
"field04": '',
"field05": '',
},
{
"field01": "three",
"field02": "03",
"field03": false,
"field04": '<input type="checkbox" ng-model="row.entity.field03" ng-click="$event.stopPropagation();getExternalScopes().showMe()">',
"field05": '<div><img class="icon" alt=""/></div>',
}
];
$scope.toggle = function() {
alert("toggled");
}
}]);
Code from index.html:
<body>
<div ng-controller="MainCtrl">
<div ui-grid="gridOptions" external-scopes="myViewModel" class="grid"></div>
</div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular-sanitize.min.js"></script>
<script src="app.js"></script>
<script type="text/ng-template" id="viewTemplate2">
<span ng-bind-html="row.entity[col.field]"></span>
</script>
</body>
I am achieving the correct effect in field03 if I write the html in the columnDef. Thanks to TomMorgan's plunker here: http://plnkr.co/edit/9eRg9Yjl2ooeSuWMJ8x2?p=preview.
I can fill the cellTemplate with html from the data in field05.
Why is it not working for my checkbox in field04?
I'm new to angularjs and its difficult to separate "ui-grid" solutions from "ng-grid" solutions. I appreciate the help.
I am not sure if I understand your code.
You shouldn't put html code in your data. So I changed it to:
$scope.gridOptions.data = [
{
"field01": "one",
"field02": "01",
"field03": false,
"field04": '',
"field05": '',
},
{
"field01": "two",
"field02": "02",
"field03": false,
"field04": '',
"field05": '',
},
{
"field01": "three",
"field02": "03",
"field03": false,
"field04": '',
"field05": '',
}
];
Next: In your cell template pass a reference to the value that changes:
{ name: 'field03', field: 'field03', cellTemplate: '<input type="checkbox"
ng-model="row.entity.field03" ng-click="$event.stopPropagation();
getExternalScopes().showMe(row.entity.field03)">'}
Note that function showMe() now has a parameter:
showMe(row.entity.field03)
In the external scope you should react to the parameter:
$scope.myViewModel = {
someProp:'abc',
showMe : function(value){
alert('toggled to: '+value);
}
};
(You don't really need someProp)
The $scope.toggle() function can be removed, or can be called from showMe().
Furthermore, I added some debugging help to your html to show you that the binding works pretty well:
<div ng-controller="MainCtrl">
<div ui-grid="gridOptions" external-scopes="myViewModel" class="grid"></div>
<hr>
{{gridOptions.data | json}}
</div>
Here is a Plunker. Is that what you want?
Update:
Here is another Plunker that has the checkbox in column 4.
Here is a Plunker with appScope, external-scopes don't work anymore.
I've made some changes to work with new appScope:
{ name: 'field03', field: 'field03', cellTemplate: '<input type="checkbox"
ng-model="row.entity.field03" ng-click="grid.appScope.showMe(row.entity.field03)">'}
In the scope you should react to the parameter but I've pulled from myViewModel and just created a function inside $scope:
$scope.showMe : function(value){
alert('toggled to: '+value);
};
You can test code from version 15 against my version 16. My new version runs ok but 15 no.
You need to use $sce to tell ng-bind-html that HTML content you are binding is safe.
I have forked your plunker and the solution for your question is http://plnkr.co/edit/JyTaF8niJlf9Wpb775kb?p=preview
app.filter('unsafe', function ($sce) {
return $sce.trustAsHtml;
});
You have to use this filter with ng-bind-html