ng-bootstrap Datepicker: Is there a way to select more than one date at once? - datepicker

I'm in need of a calendar widget and, since I'm using Bootstrap 4 and ng-bootstrap in my current project, I'd like to know if the ng-boostrap widget support the multiselection of dates in some way.
I've already tried the wijmo Calendar for multiselection, but without success. Otherwise, can you recommend me a datepicker widget that has this capability?

This can help
<p>This datepicker uses a custom template to display days.</p>
<ngb-datepicker
[showWeekNumbers]="true"
[dayTemplate]="customDay"
(dateSelect)="selectOne($event)"
></ngb-datepicker>
<ng-template
#customDay
let-date
let-currentMonth="currentMonth"
let-selected="selected"
let-disabled="disabled"
let-focused="focused"
>
<span
class="custom-day"
[class.focused]="focused"
[class.bg-primary]="isSelected(date)"
>{{ date.day }}</span
>
</ng-template>
<div *ngIf="modelList.length>0">
<h1>Selected dates:</h1>
<pre>{{modelList| json}} </pre>
</div>
TypeScript
import { Component } from '#angular/core';
import {
NgbCalendar,
NgbDate,
NgbDateStruct,
} from '#ng-bootstrap/ng-bootstrap';
#Component({
selector: 'ngbd-datepicker-customday',
templateUrl: './datepicker-customday.html',
styles: [
`
.custom-day {
text-align: center;
padding: 0.185rem 0.25rem;
border-radius: 0.25rem;
display: inline-block;
width: 2rem;
}
.custom-day:hover, .custom-day.focused {
background-color: #e6e6e6;
}
.bg-primary {
border-radius: 1rem;
}
`,
],
})
export class NgbdDatepickerCustomday {
model: NgbDateStruct;
modelList: Array<NgbDateStruct> = [];
constructor(private calendar: NgbCalendar) {}
isSelected = (date: NgbDate) => {
return this.modelList.indexOf(date) >= 0;
};
selectOne(date) {
if (this.modelList.indexOf(date) >= 0) {
this.modelList = this.modelList.filter(function (ele) {
return ele != date;
});
} else {
this.modelList.push(date);
}
console.log(this.modelList);
}
}
Demo stackblitz

Yes, the ng-bootstrap datepicker supports range selection. You'll need to do manual conversion between the NgbDateStruct and a JavaScript Date object.

Related

deleting an item from custom component (mb-bubbles) don't deletes item in items passed as property

My custom element is called "mb-bubbles". It represent a list of things. Each of these things must have at least the attributes "id" (Number) and "text" (String). If the component have the attribute "editable", you should be able to remove items ("blubbles") from it.
Its source code is:
import { LitElement, html, css } from '../vendor/lit-2.4.0/lit-all.min.js';
export class MbBlubbles extends LitElement {
static styles = [
css`
:host {
display: block;
overflow: hidden;
}
.bubble {
font-size: 14px;
line-height: 14px;
padding: 5px 10px;
border-radius: 18px;
background: #fff;
display: block;
float: left;
margin: 4px 2px;
cursor: pointer;
}
.bubble:hover {
background: #def;
}
.bubble>.remove {
display: inline-block;
line-height: 20px;
width: 20px;
border-radius: 10px;
text-align: center;
font-weight: bold;
}
.bubble>.remove:hover {
background: #fff;
}
`
];
static get properties() {
return {
items: { type: Array }, // An array of objects with 2 attributes: "id" (Number) and "text" (String).
editable: { type: Boolean }
};
}
selectItem(item) {
this.dispatchEvent(new CustomEvent('select-item', { detail: { item } }));
}
removeItem(item) {
this.items = this.items.filter(it => it.id != item.id);
}
render() {
return this.items.map(item => html`
<div class="bubble" #click="${() => this.selectItem(item)}">
${item.text}
${this.editable ? html`<span class="remove" #click="${() => this.removeItem(item)}">×</span>` : ''}
</div>
`);
}
}
customElements.define('mb-blubbles', MbBlubbles);
This component is used from outside in this way:
<mb-blubbles .items="${this.items}" editable></mb-blubbles>
${JSON.stringify(this.items)}
As you can see the property this.items seems unmodified.
How to modify the property from inside my custom component and have its changes reflected from the outside?
Is there any directive for that?
The reactive property only works within the component class, that is, updating this.items from within <mb-blubbles> will cause the contents of it to re-render, but it won't cause the parent to re-render, because the reactivity is based on the accessor of the component class itself.
If you need this to be updated in the parent, it would be better for the removeItems() method to dispatch an event, just like you're doing with the selectItem, and have the parent listen for that and update its own this.items.
class MbBlubbles extends LitElement {
...
removeItem(item) {
this.dispatchEvent(new CustomEvent('remove-item', { detail: { item } }));
}
...
}
class ParentElement extends LitElement {
static properties = { items: { type: Array } };
removeItem(event) {
const { item } = event.detail;
this.items = this.items.filter(it => it.id != item.id);
}
render() {
return html`
<mb-blubbles #remove-item=${this.removeItem} .items=${this.items} editable></mb-blubbles>
${JSON.stringify(this.items)}
`;
}
}
Here's a working playground: https://lit.dev/playground/#gist=f61456f62076b849c0af02b2b1c7aff6

How to add custom toggle button in formsflow.ai

I am using latest version of formsflow.ai and I want to create a custom toggle button. How can I do that in formflow.ai. I refer the following documents of formio to do that.
I am expecting to include a custom toggle button in drag and drop mechanism of formsflow.ai
step 1:create the components inside the forms-flow-web in the following order
step 2:Toggle.js code
import React from "react";
import ReactDOM from "react-dom";
import { ReactComponent } from "react-formio";
import settingsForm from "./Toggle.settingsForm";
import ToggleCustomComp from "./Togglechange";
export default class Toggle extends ReactComponent {
/**
* This function tells the form builder about your component. It's name, icon and what group it should be in.
*
* #returns {{title: string, icon: string, group: string, documentation: string, weight: number, schema: *}}
*/
static get builderInfo() {
return {
title: "Toggle",
icon: "square",
group: "basic",
documentation: "",
weight: 120,
schema: Toggle.schema()
};
}
/**
* This function is the default settings for the component. At a minimum you want to set the type to the registered
* type of your component (i.e. when you call Components.setComponent('type', MyComponent) these types should match.
*
* #param sources
* #returns {*}
*/
static schema() {
return ReactComponent.schema({
type: "toggleCustomComp",
label: "ToggleButton"
});
}
/*
* Defines the settingsForm when editing a component in the builder.
*/
static editForm = settingsForm;
/**
* This function is called when the DIV has been rendered and added to the DOM. You can now instantiate the react component.
*
* #param DOMElement
* #returns ReactInstance
*/
attachReact (element) {
let instance;
return ReactDOM.render(
<ToggleCustomComp
ref={(refer) => {instance = refer;}}
component={this.component} // These are the component settings if you want to use them to render the component.
value={this.datavalue} // The starting value of the component.
onChange={this.updateValue}
data={this.data}
disabled={this.disabled}
// The onChange event to call when the value changes.
/>,
element,() => (this.reactInstance = instance)
);
}
/**
* Automatically detach any react components.
*
* #param element
*/
detachReact(element) {
if (element) {
ReactDOM.unmountComponentAtNode(element);
}
}
}
step 3:Toggle.settingsForm.js
import baseEditForm from 'formiojs/components/_classes/component/Component.form';
const settingsForm = (...extend) => {
return baseEditForm([
{
key: 'display',
components: [
{
// You can ignore existing fields.
key: 'placeholder',
ignore: true,
},
]
},
{
key: 'data',
components: [],
},
{
key: 'validation',
components: [],
},
{
key: 'api',
components: [],
},
{
key: 'conditional',
components: [],
},
{
key: 'logic',
components: [],
},
], ...extend);
}
export default settingsForm;
step 4:Togglechange.jsx
import React, {Component} from 'react';
import '../Toggle/toggle.css';
/**
* An example React component this is simply a controlled input element.
*
*/
export default class ToggleCustomComp extends Component {
constructor(props) {
super(props);
this.state = {
value: props.value
}
}
updateCommentData = (event) => {
//const {type} = this.props.component;
this.setState({value: {checked:event.target.checked}}, () => this.props.onChange(this.state.value));
};
render() {
const {disabled, name} = this.props;
let { value } = this.state;
const checked = value?.checked || false;
return (
/*<input type="text" value={value} className={this.props.component.customClassName} onChange={this.setValue}></input>*/
// <input type="checkbox" id="vehicle3" name="vehicle3" value="Boat"></input>
<label class="switch">
<input
name={name}
value={checked}
type="checkbox"
className="form-control"
onChange={(e)=>this.updateCommentData(e)}
disabled={disabled}
/>
<span class="slider round" />
</label>
);
}
};
step 5 :css file
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: #2196F3;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
step 6:index.js file
import TextAreaWithAnalytics from "./TextAreaWithAnalytics/TextAreaWithAnalytics";
import Toggle from "./Toggle/Toggle";
const components = {
textAreaWithAnalytics: TextAreaWithAnalytics,
toggleCustomComp: Toggle
};
export default components;

IONIC 4 : getActiveIndex() is not working in ion-slides

Using IONIC 4 ion-slides, I am trying to get currently clicked silde index using getActiveIndex() as below which it is not working.
<ion-slides #testSlider (ionSlideTap)="getIndex()">
<ion-slide>....</ion-slide>
</ion-slides>
#ViewChild('testSlider') slider: ElementRef; // first way
getIndex() {
this.slider.nativeElement.getActiveIndex();
}
#ViewChild('testSlider') slider: Slider; //second way
getIndex() {
this.slider.getActiveIndex();
}
And the another way as below which is also not working:
<ion-slides #testSlider (ionSlideTap)="getIndex(testSlider)">
<ion-slide>....</ion-slide>
</ion-slides>
getIndex(testSlider) {
testSlider.getActiveIndex();
}
Can anyone please suggest me how can I get active index or currently clicked slide index in IONIC 4 ?
I had the same problem, but managed to solve it as follows:
export class SomePage implements OnInit {
...
currentIndex:Number = 0;
...
getSlideIndex(){
this.slides.getActiveIndex().then(
(index)=>{
this.currentIndex = index;
});
}
...
this.getSlideIndex();
console.log(this.currentIndex);
Note that although it seems to work, I suspect that because the value is changes inside promise, it will only return the correct value if it has not recently changed. I thus intend to update this with a wait implemented to counter this.
in template
<ion-slides pager="true" (ionSlideDidChange)="slideChanged($event)" #slides>
</ion-slides>
in component
import { IonSlides } from '#ionic/angular';
#ViewChild('slides', {static: true}) slides: IonSlides;
slideChanged(e: any) {
this.slides.getActiveIndex().then((index: number) => {
console.log(index);
});
}
According to the documentation, getActiveIndex() returns a Promise<number>.
So by using ionSlideTap:
<ion-slides (ionSlideTap)="onSlideTapped($event)">
...
</ion-slides>
I found two ways to do it:
As phunder suggests, you can use then() to retrieve its value. I also did it with async/await:
async onSlideTapped(event: any) {
const index: number = await event.target.getActiveIndex();
console.log(index);
}
Or you can use the swiper object:
onSlideTapped(event: any) {
console.log(event.target.swiper.clickedIndex);
}
Therefore, you don't have to listen for every changes or to import the IonSlides in your component.
UPDATED:
I think I made a few mistakes, here is working example (Ionic 3). Please make sure you are using $event.
Template file:
<ion-slides (ionSlideTap)="getIndex($event)">
<ion-slide>1</ion-slide>
</ion-slides>
Now in TS file:
getIndex(event) {
console.log(event.clickedIndex);
}
Try the above approach?
Here is working stackblitz: https://stackblitz.com/edit/ionic-ssvout
1)Assign id to the respective like #slides
<div>
<ion-slides #slide (ionSlideDidChange)="SlideChanges(slide)">
</ion-slides>
</div>
2) import IonSlides in your.ts page/component
import { IonSlides } from '#ionic/angular';
3). Use method
SlideChanges(slide: IonSlides) {
slide.getActiveIndex().then((index: number) => {
this.yourSlideIndex= index;
alert(this.yourSlideIndex)
});
}
for ionic 4
*.html
<ion-slides #slides (ionSlideDidChange)="slideChanged(slides)">
...
</ion-slides>
*. ts
...
#ViewChild('slides', { static: false }) slides: IonSlides;
...
slideChanged(slides: IonSlides) {
slides.getActiveIndex().then((index: number) => {
console.log(index);
this.currentIndex = index;
});
}
Yes, It's working...!
// Typescript
import { IonSlides } from '#ionic/angular';
// in Component Class
export class AppComponent implements OnInit {
#ViewChild('contentSlider') contentSlider: IonSlides;
constructor(){}
ngOnInit() {}
do_getActiveSlide(e: any) {
this.contentSlider.getActiveIndex().then((index: number) => {
console.log("Current active slide index", index);
});
}
}
div {
width: 100%;
height: 5em;
color: gold;
background-color: #333;
margin: 1.5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/#ionic/core/dist/ionic/ionic.esm.js"></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/#ionic/core/dist/ionic/ionic.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/#ionic/core/css/ionic.bundle.css"/>
<ion-slides pager="true" (ionSlideDidChange)="do_getActiveSlide($event)" #contentSlider>
<ion-slide>
<div>1</div>
</ion-slide>
<ion-slide>
<div>2</div>
</ion-slide>
<ion-slide>
<div>3</div>
</ion-slide>
</ion-slides>

What is the use of & in scss of some page

I have not understood the use of '&' in scss of some page and also the scss I have not understood.
some-page.scss
some-page-selector {
& ion-item {
&.item {
//some properties
&[margin-bottom] {
//some property
}
& ion-avatar {
//some property
}
& ion-avatar ion-img,
& ion-avatar img {
//some property
}
}
In Sass, the & (ampersand) references the parent (or chain of parents) of a block of code.
Given this SCSS (similar to what you posted) ...
page {
& ion-item { // => page ion-item
&.item { // => page ion-item.item
color: red;
&[margin-bottom] { // => page ion-item.item[margin-bottom]
margin-bottom: 1em;
}
& ion-avatar { // => page ion-item.item ion-avatar
font-weight: bold;
}
}
}
}
... you will get this compiled CSS:
page ion-item.item {
color: red;
}
page ion-item.item[margin-bottom] {
margin-bottom: 1em;
}
page ion-item.item ion-avatar {
font-weight: bold;
}

how to show data of model.ts in my code, using ionic 2

now i trying array data modeling using ionic2.
i created 'model.ts' in 'src/app/models' and declared in 'setting.ts' with array data.
next, i called it to 'setting.html'.
By the way...There is a some problem.
build and run were success. but any datas didn't show in screen..
not Error, i dont know where is wrong..
please find wrong point and fix that.
there is my code..
workoutlist-model.ts
export class WorkoutlistModel {
constructor(public Workoutlist: any[]) {
this.Workoutlist = [];
}
addItem(nm, gl) {
this.Workoutlist.push({
name: nm,
goal: gl
});
}
removeItem(nm, gl) {
for (var i = 0; i < this.Workoutlist.length; i++) {
if (this.Workoutlist[i].name == nm) {
if (this.Workoutlist[i].goal == gl) {
this.Workoutlist.splice(i);
}
}
}
}
}
setting.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { WorkoutlistModel } from '../../app/models/workoutlist-model';
#Component({
selector: 'page-setting',
templateUrl: 'setting.html'
})
export class Setting {
constructor(public navCtrl: NavController) {
new WorkoutlistModel([{ name: 'Push-Up', goal: 100 },
{ name: 'Squat', goal: 150 },
{ name: 'Sit-Up', goal: 45 }]);
}
}
setting.html - the part using this.
<ion-content style="height: 200px; outline: green">
<ion-card *ngFor="let WO of WorkoutlistModel;">
<button ion-item>
<div style="float: left;padding: 0px;">name : {{WO.name}}</div>
<div style="float: right;padding: 0px;">goal : {{WO.goal}}</div>
</button>
</ion-card>
</ion-content>
You havent declared or assigned WorkoutlistModel
Also WorklistModel is class and not an array to traverse with *ngFor
export class Setting {
workListModel:any;//declare
constructor(public navCtrl: NavController) {
this.workListModel = new WorkoutlistModel([{ name: 'Push-Up', goal: 100 },
{ name: 'Squat', goal: 150 },
{ name: 'Sit-Up', goal: 45 }]);//assign
}
}
In Html
<ion-card *ngFor="let WO of workListModel.getList();"><!-- get the list of items from class to traverse. may have to create this function -->
<button ion-item>
<div style="float: left;padding: 0px;">name : {{WO.name}}</div>
<div style="float: right;padding: 0px;">goal : {{WO.goal}}</div>
</button>
</ion-card>
You are not injecting the model. So change it to this.
constructor( Workoutlist: any[]) {
this.Workoutlist = Workoutlist;
}