Currently I am using:
ng-bootstrap 1.0.0-alpha.24
angular/core 4.0.0
bootstrap 4.0.0-alpha.6
I wanted to ask if someone knows how to autoclose the datepicker
when the focus is lost or another datepicker is opened.
Also i wanted to now if it is possible to close the datepicker in the component code with typescript.
It would be nice if someone could provide a working plunker or a code snippet.
My actual implementation:
<div class="input-group">
<input class="rect-border full-width"
placeholder="YYMMDD"
[(ngModel)]="selectedDate"
ngbDatepicker
#datePickerInput="ngbDatepicker"
(keydown.arrowup)="incrementDate()"
(keydown.arrowdown)="decrementDate()"
(ngModelChange)="validate('modelChanged')"
(blur)="validate(null)"
[disabled]="disabled"
[ngClass]="{'input-required': required, 'normal-color': valid, 'picker-disabled': disabled}">
<div class="input-group-addon rect-border"
(click)="disabled ? true : datePickerInput.toggle()"
[ngClass]="{'picker-button-disabled': disabled}">
<img src="assets/img/calendar-icon.svg" class="datpickerToggle"/>
</div>
</div>
Plunker: ng-bootstrap team demo
I have searched a long time and I am also pretty new to angular and these things.
Thank you for your help!
Update:
Possible solution:
There were a lot of good solutions provided.
I also found out by myself that I could use the class NgbInputDatepicker
to close the datePicker (I always used NgbDatepicker, so it didn't work).
#ViewChild('datePickerInput') datePicker: NgbInputDatepicker;
this.datePicker.close();
you can open and close your datepicker from your html itself
for eg:
<div class="input-group">
<input class="rect-border full-width"
placeholder="YYMMDD"
[(ngModel)]="selectedDate"
ngbDatepicker
#datePickerInput="ngbDatepicker"
(keydown.arrowup)="incrementDate()"
(keydown.arrowdown)="decrementDate()"
(ngModelChange)="validate('modelChanged')"
(blur)="validate(null)"
[disabled]="disabled"
[ngClass]="{'input-required': required, 'normal-color': valid, 'picker-disabled': disabled}">
<div class="input-group-addon rect-border"
(click)="disabled ? true : datePickerInput.toggle()"
[ngClass]="{'picker-button-disabled': disabled}">
<img src="assets/img/calendar-icon.svg" class="datpickerToggle"/>
</div>
</div>
<div (click)="datePickerInput.open()"></div>
<span (click)="datePickerInput.close()"></span>
and also there are many functions which you can use in your html. some are close(), isOpen(), manualDateChange(), open(), toggle(), validate() etc. You can refer it in this plunkr http://plnkr.co/edit/G1b6fFrtVZwEz4lsou8n?p=preview
In typescript you can simply define a variable datepickerVisibility and then in your template use *ngIf to show or hide your datepicker component. Here is a demo code:
Template: <datepicker *ngIf="datepickerVisibility" [ngModel]="date"> </datepicker>
Component: private datepickerVisibility: boolean = false;
// Show the datepicker
showDatepicker() {
this.datepickerVisibility = true;
}
Edit:
Therefore you could use jQuery. Add the jQuery js into your index.html and in your typescript component use jQuery as follows:
declare let jQuery: any;
#Component({
moduleId: module.id,
selector: 'test',
templateUrl: 'template.html',
styleUrls: ['test.css'],
})
export class TestComponent {
constructor() {}
public toggleDatepicker() {
jQuery("#datepicker01").toggle();
}
}
And in your template file just add the id datepicker01 to your datepicker div
<div id="datepicker01" ...>
I was looking for a solution to this issue, but in a scenario where the datepicker is wrapped in a custom component and has to expose a function a parent component can call to toggle the datepicker. The answers provided are great and will work for most use case, but not mine, as I didn't want to add a jQuery dependency and calling toggle from the HTML isn't an option.
Here's how I solved it.
I added a ViewChild reference to the datepicker input in the *.component.ts file
#ViewChild('d', {static: true}) d;
that matches the datepicker identifier in the HTML file
<input (dateSelect)="dateSelected($event)" class="form-control" (focus)='d.toggle()' placeholder="yyyy-mm-dd" name="d"
[ngModelOptions]="{standalone: true}" [(ngModel)]="date" ngbDatepicker #d="ngbDatepicker">
and called the toggle function within a method exposed by the component
toggle() {
this.d.toggle();
}
That way, another component can call the toggle() function exposed by this component to toggle the datepicker like so:
In HTML
<app-custom-datepicker #date></app-custom-date-picker>
In .ts file
#ViewChild('date', {static: true}) date;
.
.
.
this.date.toggle();
Related
I have 2 strange problems. I have a large form with lots of input fields. That works fine. I want to add a slide toggle at the bottom which changes a variable that will affect styles on the whole form.
My first problem is that the variable will not display until the slide toggle is clicked.
HTML
<mat-slide-toggle [(ngModel)]="ifPrint" name="ifPrint" id="ifPrint" ></mat-slide-toggle>
<div>
{{ifPrint}}
</div>
COMPONENT
export class PrintReviewDetailsComponent implements OnInit {
ifPrint = true;
}
the ifPrint variable is blank on page load
The second problem is
when the slide toggle is clicked the div containing the variable shows as true but when I click the toggle to the off position the ifPrint variable stays as true and does not change.
I have created a blitz and it is working fine there with the same code so I am unsure as why I am having these issues on my page.
The console says:
Error: No value accessor for form control with name: 'ifPrint'
EDIT: I updated the stackblitz to include the html of the form and now it is not working.
Your updated stackblitz couldn't recreate the issue which you shared... But from your question, the following 2 issues are addressed for a form and styling is also done:
the toggle value was not displayed by-default until the toggle was clicked
the toggle value didn't change when you toggled it
the style is now being updated based on the toggle value
relevant TS:
model:any;
constructor(){
this.model = {name: '' , age: null, ifPrint: false};
}
relevant HTML:
<form (ngSubmit)="formSubmit()" #demoForm="ngForm" >
<div [ngClass]="model.ifPrint === true ? 'trueClass' : 'falseClass'">
<input type="text" placeholder="Enter Name" #name="ngModel" [(ngModel)]="model.name" name="name" />
<br/>
<input type="number" placeholder="Enter Age" #age="ngModel" [(ngModel)]="model.age" name="age" /> <br/>
<mat-slide-toggle #ifPrint #age="ngModel" [(ngModel)]="model.ifPrint" name="ifPrint"></mat-slide-toggle> {{model.ifPrint}} <br/>
</div>
<button type="submit"> Submit </button>
</form>
check a minimal, working demo here for what you're trying... hope it helps...
I removed everything in your template except the mat-slide-toggle and it works as expected.
I believe the issue is because your html template is referencing methods or properties that your component does not have, or trying to access a property of null or undefined somewhere is causing the issue.
Check your console for the errors and if you fix those up, the slide toggle should work as expected.
I am building a single application using Angular 5. I create a form using the Reactive Forms of Angular.
In the input I use the HTML5 validation attribute required. When I submit the form and input is left empty, I would expect the browsers built in validation of the input:
But nothing.
Is Angular suppressing the browsers built in behavior of validating the required input field? Can I activate it and still using FormBuilder?
import {Component} from '#angular/core';
import {FormBuilder, FormGroup} from '#angular/forms';
#Component({
selector: 'app-system-create',
templateUrl: './system-create.component.html',
styleUrls: ['./system-create.component.scss']
})
export class SystemCreateComponent {
form: FormGroup;
constructor(
private fb: FormBuilder
) {
this.form = fb.group({
shortName: ''
});
}
onSubmit() {
console.log("on submit");
}
}
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div class="form-element">
<label>short name</label>
<input class="form-control" formControlName="shortName" type="text" placeholder="e.g. SYS" id="systemForm_shortName" required>
</div>
<button class="btn btn-primary" type="submit">Speichern</button>
</form>
You should try adding the attribute ngNativeValidate in your form element to prevent Angular from adding the novalidate html attribute. As explained in the Angular NgNoValidate directive documentation.
If you want to use native validation with Angular forms, just add ngNativeValidate attribute
I have an Angular 2 form with lots of required fields. Those have Validators.required assigned. I want to add an asterisk to these fields' labels.
<form [formGroup]="form">
<div class="form-group row">
<label class="col-sm-3 col-form-label">First Name -> Add asterisk here</label>
<div class="col-sm-9">
<input formControlName="firstName" type="text" class="form-control">
</div>
</div>
...
I have googled and read the docs, but can't find an implementation for this use case.
I know I can add the required attribute manually and work from there, but I would prefer to avoid as this seems redundant with the validator assignment.
Not sure, if its the best ng2-style solution, but what about this:
Let your FormComponent hold an array of required fields. In your template you can simply use something like:
<label for="firstName">
FirstName <span *ngIf="isFieldRequired('firstName')"> *</span>
</label>
You can create separate component for Label with asterisk, if you don't want to repeat the code through your template, for example:
#Component({
selector: 'my-label',
template: `<label for="{{id}}">{{label}} <span *ngIf="isFieldRequired(id)"> *</span></label>`
})
export class MyLabelComponent {
#Input() label: string;
#Input() id: string;
#Input() requires: [];
constructor() { }
isFieldRequired(id) {
return this.requires.indexOf(id) !== -1; // check if the array contains the value
}
}
In your Form Component, you just pass values to the my-label component, like:
<my-label [requires]="requiredFields" [label]="'Name'" [id]="'name'"></my-label>
Here is working plunker of this example: http://plnkr.co/edit/M66IFQGhhe82mNt3ekxw?p=preview
with the idea how to use the required definition together with more custom validators. See app.component.ts
The site I'm currently working on is built in Drupal 7. I have one form that requires user input so I'm attempting to build it with VueJS. The form is contained all within one template file (.tpl.php) and all the content is provided in this template file or via the VueJS Javascript (nothing is coming from the CMS).
The issue I have is that the Vue components are not rendering on the front-end, but when I copy the code into a JSFiddle they do, so I'm guessing it is an issue with the interaction between VueJS and Drupal. Here is a screenshot of my markup when inspecting...
Here is the code from the .tpl.php file...
<div id="app">
<form>
<div>
<label for="year">Per Year</label>
<input type="radio" name="frequency" id="year" value="year" v-model="frequency" checked>
<label for="month">Per Month</label>
<input type="radio" name="frequency" id="month" value="month" v-model="frequency">
</div>
</form>
<ul class="plans">
<template id="plan-component">
<h2 class="plan-name">{{ name }}</h2>
<h2 class="plan-cost">{{ price }}</h2>
<h2 class="plan-tagline">{{ tagline }}</h2>
Choose this plan
</template>
<li>
<plan-component :frequency="frequency"
name="Basic"
tagline="Basic tagline"
price-yearly="Free"
price-monthly="Free"
></plan-component>
</li>
<li>
<plan-component :frequency="frequency"
name="Rec"
tagline="Rec tagline"
price-yearly="3"
price-monthly="4"
></plan-component>
</li>
<li>
<plan-component :frequency="frequency"
name="Team"
tagline="Team tagline"
price-yearly="4"
price-monthly="5"
></plan-component>
</li>
<li>
<plan-component :frequency="frequency"
name="Club"
tagline="Club tagline"
price-yearly="5"
price-monthly="6"
></plan-component>
</li>
</ul>
</div>
..and the code from my JS file...
Vue.component('plan-component', {
template: '#plan-component',
props: ['frequency', 'name', 'tagline', 'priceYearly', 'priceMonthly'],
computed: {
'price': function() {
if (this.frequency === 'year') {
return this.priceYearly;
} else {
return this.priceMonthly;
}
}
},
methods: {
makeActivePlan() {
// We dispatch an event setting this to become the active plan
this.$dispatch('set-active-plan', this);
}
}
});
new Vue({
el: '#app',
data: {
frequency: 'year',
activePlan: {name: 'no', price: 'You must select a plan!' }
},
events: {
'set-active-plan': function(plan) {
this.activePlan = plan;
}
},
});
And here is the JSFiddle which outputs the components correctly - https://jsfiddle.net/2xgrpLm6/
What browser are you using? <template> tags are not supported in IE.
Another idea is to make sure you are never using fragment components (meaning wrap everything inside your template with a div like so:
<template id="foobar">
<div>
CONTENT HERE
</div>
</template>
Lastly, have you turned on Vue debug mode? Before you instantiate your Vue instance, set Vue.config.debug = true and see if you get console errors then.
Try moving the <template id="plan-component">...</template> code outside of the Vue instance. I.e., such that it is not contained within <div id="app">...</div>.
This has solved a similar problem for me in the past, though I'm not sure if it applies here.
For anyone having a similar issue, the solution was simple. After Jeff suggested turning on Vue debug mode (and downloading the Dev version of Vue JS instead of minified - https://vuejs.org/guide/installation.html) the console gave the error [Vue warn]: Cannot find element: #app.
The issue was that Drupal was loading my scripts in the <head>, before <div id="app"> was loaded in the DOM. As such #app couldn't be found. After outputting the scripts before the closing <body> tag all was sorted. See here for more information [Vue warn]: Cannot find element
Similar to Angular2 two-way data binding, I have a parent and a child component. In the parent I change the value that is passed to the child component via property. The property of the child is named percentage.
https://gist.github.com/ideadapt/59c96d01bacbf3222096
I want to bind the property value to a html attribute value. Like: <div style="width: {{percentage}}%">. I didn't find any syntax that worked. So I ended up using a change listener that does some manual DOM update:
this.progressElement = DOM.querySelector(element.nativeElement, '.progress');
DOM.setAttribute(this.progressElement, "style", `width: ${this.percentage}%`);
Is there a more elegant way to accomplish this?
You can use percentage binding for CSS properties: [style.width.%]
import {Component, Input} from 'angular2/core';
#Component({
selector: 'progress-bar',
template: `
<div class="progress-bar">
<div [style.width.%]="value"> {{ value }}% </div>
</div>
`,
})
export class ProgressBar {
#Input() private value: number;
}
Use NgStyle, which works similar to Angular 1. Since alpha-30, NgStyle is available in angular2/directives:
import {NgStyle} from 'angular2/directives';
Then include NgStyle in the directives list, this should work (here are some examples):
#View({
directives: [NgStyle]
template: `
<div class="all">
<div class="progress" [ng-style]="{'width': percentage + '%'}"></div>
<span class="label">{{percentage}}</span>
</div>
`
})
Alternatively and without using NgStyle, this would work well too:
<div class="progress" [style.width]="percentage + '%'"></div>