How to use Bootstrap accordion with angular2 (HTML5 mode/hashbag in angular2) - accordion

I'm trying to use bootstrap accordion but both (angular2 and bootstrap accordian) plays around hash location.
So is there something like html5 mode in angular2?

try this
/// <reference path="../../../typings/tsd.d.ts" />
import {
Component, View,
Directive, LifecycleEvent,
EventEmitter, ElementRef,
CSSClass, ViewContainerRef, TemplateRef
} from 'angular2/angular2';
// todo: support template url
#Component({
selector: 'accordion, [accordion]',
properties: [
'templateUrl',
'bCloseOthers: closeOthers'
]
})
#View({
template: `
<div class="panel-group">
<ng-content></ng-content>
</div>
`
})
export class Accordion {
private templateUrl:string;
private bCloseOthers:any;
private groups:Array<any> = [];
constructor() {
}
public closeOthers(openGroup:AccordionGroup) {
if (!this.bCloseOthers) {
return;
}
this.groups.forEach((group:AccordionGroup) => {
if (group !== openGroup) {
group.isOpen = false;
}
});
}
public addGroup(group:AccordionGroup) {
this.groups.push(group);
}
public removeGroup(group:AccordionGroup) {
let index = this.groups.indexOf(group);
if (index !== -1) {
this.groups.slice(index, 1);
}
}
}
#Directive({
selector: 'accordion-transclude, [accordion-transclude]',
properties: ['headingTemplate: accordion-transclude'],
lifecycle: [LifecycleEvent.onInit]
})
export class AccordionTransclude {
private headingTemplate: TemplateRef;
constructor(private viewRef: ViewContainerRef) {
}
onInit() {
if (this.headingTemplate) {
this.viewRef.createEmbeddedView(this.headingTemplate);
}
}
}
import {Collapse} from '../collapse/collapse';
// todo: support template url
// todo: support custom `open class`
#Component({
selector: 'accordion-group, [accordion-group]',
properties: [
'templateUrl',
'heading',
'isOpen',
'isDisabled'
],
host: {
'[class.panel-open]': 'isOpen'
},
lifecycle: [LifecycleEvent.onInit, LifecycleEvent.onDestroy]
})
#View({
template: `
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a href tabindex="0" class="accordion-toggle"
(^click)="toggleOpen($event)">
<span [class]="{'text-muted': isDisabled}"
[accordion-transclude]="headingTemplate">{{heading}}</span>
</a>
</h4>
</div>
<div class="panel-collapse collapse" [collapse]="!isOpen">
<div class="panel-body">
<ng-content></ng-content>
</div>
</div>
</div>
`,
directives: [Collapse, AccordionTransclude, CSSClass]
})
export class AccordionGroup {
private templateUrl:string;
private _isOpen:boolean;
public isDisabled:boolean;
public headingTemplate:any;
public templateRef: any;
constructor(private accordion:Accordion) {
}
onInit() {
this.accordion.addGroup(this);
}
onDestroy() {
this.accordion.removeGroup(this);
}
public toggleOpen(event:MouseEvent) {
event.preventDefault();
if (!this.isDisabled) {
this.isOpen = !this.isOpen;
}
}
public get isOpen():boolean {
return this._isOpen;
}
public set isOpen(value:boolean) {
this._isOpen = value;
if (value) {
this.accordion.closeOthers(this);
}
}
}
#Directive({
selector: 'accordion-heading, [accordion-heading]'
})
export class AccordionHeading {
constructor(private group:AccordionGroup, private templateRef: TemplateRef) {
group.headingTemplate = templateRef;
}
}
export const accordion:Array<any> = [
Accordion, AccordionGroup,
AccordionHeading, AccordionTransclude];

Related

Why not showing liked icon when page refresh in ionic

I am making like and dislike functionality in ionic app when user like then want to show heart icon and when user dislike then want to show empty heart icon.When like the post then icon show but when refreshing page then its show icon of empty likes.Please help me how to resolve this problem in ionic....
tab1.page.html
<div>
<img src="{{getImage.image}}" (click)="tapPhotoLike(getImage.id)" (click)="toggleIcon(getImage.id)">
</div>
<p no-margin no-padding>
<button clear ion-button icon-only class="like-btn">
<!-- <ion-icon no-padding name="like_btn.icon_name" color="{{ like_btn.color }}" class="icon-space"></ion-icon> -->
<ion-icon name="heart-empty" *ngIf="!iconToggle[getImage.id]" color="{{ like_btn.color }}"></ion-icon>
<ion-icon name="heart" *ngIf="iconToggle[getImage.id]" color="{{ like_btn.color }}"></ion-icon>
</button>
</p>
tab1.page.ts
import { Component, OnInit } from '#angular/core';
import { UserService } from '../user.service';
import { User } from '../user';
import { first } from 'rxjs/operators';
import { Storage } from '#ionic/storage';
import { ToastController } from '#ionic/angular';
import { LoadingController, NavController } from '#ionic/angular';
#Component({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
export class Tab1Page implements OnInit {
num
getImages: User[] = [];
getImages2: User[] = [];
getImages3 = [];
getcounts;
countLikes
counts
unlikes
likesID
iconToggle = [];
like_btn = {
color: 'danger',
icon_name: 'heart-empty'
};
public tap: number = 0;
public status: false;
constructor(private userService: UserService,
public toastController: ToastController,
private storage: Storage,
public navCtrl: NavController,
public loadingController: LoadingController) {
}
doRefresh(event) {
this.userPost();
setTimeout(() => {
event.target.complete();
}, 2000);
}
ngOnInit() {
this.userPost();
//this.getCountOfLikes();
}
async userPost() {
const loading = await this.loadingController.create({
message: 'Please wait...',
spinner: 'crescent',
duration: 2000
});
await loading.present();
this.userService.getUserPost().pipe(first()).subscribe(getImages => {
this.getImages3 = getImages;
loading.dismiss();
});
}
likeButton() {
const detail_id = this.userService.getCurrentIdpostId();
this.storage.get('userId').then((val) => {
if (val) {
let user_id = val
this.userService.userPostLikes(user_id, detail_id).pipe(first()).subscribe(
async data => {
this.iconToggle[this.num] = true;
if (data['status'] === 'you have already liked this post') {
const toast = await this.toastController.create({
message: 'you have already liked this post before.',
duration: 2000
});
toast.present();
}
this.userPost();
}
);
}
});
}
tapPhotoLike($detail_id, num) {
this.userService.setCurrentIdpostId($detail_id);
this.tap++;
setTimeout(() => {
if (this.tap == 1) {
this.tap = 0;
//this.unlikePost();
} if (this.tap > 1) {
this.tap = 0;
}
}, 250);
}
setIconToggles() {
let x = 0;
this.getImages3.forEach(() => {
this.iconToggle[x] = false;
x++;
});
}
toggleIcon(num) {
if (this.iconToggle[num]) {
this.iconToggle[num] = false;
this.unlikePost();
} else {
this.iconToggle[num] = true;
this.likeButton();
}
}
ionViewWillEnter() {
this.userPost();
}
unlikePost() {
let detail_id = this.userService.getCurrentIdpostId();
this.storage.get('userId').then((val) => {
if (val) {
let user_id = val;
this.userService.unLikes(user_id, detail_id).subscribe(async dislikes => {
this.unlikes = dislikes;
this.iconToggle[this.num] = false;
this.userPost();
})
}
});
}
}
How manage icon , i am inserting status on like and dislike in database..In this code how to manage status please help me.

displaying a message in angular 6

hello I'm learning angular 6 but I don't understand why it doesn't display my message but he appears in the logs of my server.
component:
import { Component } from '#angular/core';
import { ChatService } from '../chat.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
message: string;
messages: string[] = [];
constructor(private chatService: ChatService) {
}
sendMessage() {
this.chatService.sendMessage(this.message);
this.message = '';
}
OnInit() {
this.chatService
.getMessages()
.subscribe((message: string) => {
this.messages.push(message);
});
}
}
html:
<div>
<li *ngFor="let message of messages">
{{message}}
</li>
</div>
<input [(ngModel)]="message" (keyup)="$event.keyCode == 13 && sendMessage()" />
<button (click)="sendMessage()">Send</button>
thanks for your help
chat service :
import * a io from 'socket.io-client';
import {Observable} from 'rxjs';
export class ChatService{
private url = 'http://localhost:3000';
private socket;
constructor() {
this.socket = io(this.url);
}
public sendMessage(message){
this.socket.emit('new-message',message);
}
public getMessage = () => {
return Observable.create((observer) => {
this.socket.on('new-message' , (message) => {
observer.next(message);
});
});
}
}

Angular 2 Custom Validator (Template Form) Validation

I am trying to implement a custom validator that checks if the keyed username exists. However, I am running into a problem where the control is always invalid. I have confirmed the webApi is returning the correct values and the validator function is stepping into the proper return statements.
My custom validator is as follows:
import { Directive, forwardRef } from '#angular/core';
import { AbstractControl, ValidatorFn, NG_VALIDATORS, Validator, FormControl } from '#angular/forms';
import { UsersService } from '../_services/index';
import { Users } from '../admin/models/users';
function validateUserNameAvailableFactory(userService: UsersService): ValidatorFn {
return (async (c: AbstractControl) => {
var user: Users;
userService.getUserByName(c.value)
.do(u => user = u)
.subscribe(
data => {
console.log("User " + user)
if (user) {
console.log("Username was found");
return {
usernameAvailable: {
valid: false
}
}
}
else {
console.log("Username was not found");
return null;
}
},
error => {
console.log("Username was not found");
return null;
})
})
}
#Directive({
selector: '[usernameAvailable][ngModel]',
providers: [
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => UserNameAvailableValidator), multi: true }
]
})
export class UserNameAvailableValidator implements Validator {
validator: ValidatorFn;
constructor(private usersService: UsersService) {
}
ngOnInit() {
this.validator = validateUserNameAvailableFactory(this.usersService);
}
validate(c: FormControl) {
console.log(this.validator(c));
return this.validator(c);
}
}
And the form looks like:
<form #userForm="ngForm" (ngSubmit)="onSubmit()" novalidate>
<div class="form form-group col-md-12">
<label for="UserName">User Name</label>
<input type="text" class="form-control" id="UserName"
required usernameAvailable maxlength="50"
name="UserName" [(ngModel)]="user.userName"
#UserName="ngModel" />
<div [hidden]="UserName.valid || UserName.pristine" class="alert alert-danger">
<p *ngIf="UserName.errors.required">Username is required</p>
<p *ngIf="UserName.errors.usernameAvailable">Username is not available</p>
<p *ngIf="UserName.errors.maxlength">Username is too long</p>
</div>
<!--<div [hidden]="UserName.valid || UserName.pristine" class="alert alert-danger">Username is Required</div>-->
</div>
</form>
I have followed several tutorials proving this structure works, so I am assuming that I am possibly messing up the return from within the validator function.
Also, is there a way I can present the list of errors (I have tried using li with ngFor, but I get nothing from that)?
So, there was something wrong with using .subscribe the way I was. I found a solution by using the following 2 links:
https://netbasal.com/angular-2-forms-create-async-validator-directive-dd3fd026cb45
http://cuppalabs.github.io/tutorials/how-to-implement-angular2-form-validations/
Now, my validator looks like this:
import { Directive, forwardRef } from '#angular/core';
import { AbstractControl, AsyncValidatorFn, ValidatorFn, NG_VALIDATORS, NG_ASYNC_VALIDATORS, Validator, FormControl } from '#angular/forms';
import { Observable } from "rxjs/Rx";
import { UsersService } from '../_services/index';
import { Users } from '../admin/models/users';
#Directive({
selector: "[usernameAvailable][ngModel], [usernameAvailable][formControlName]",
providers: [
{
provide: NG_ASYNC_VALIDATORS,
useExisting: forwardRef(() => UserNameAvailableValidator), multi: true
}
]
})
export class UserNameAvailableValidator implements Validator {
constructor(private usersService: UsersService) {
}
validate(c: AbstractControl): Promise<{ [key: string]: any }> | Observable<{ [key: string]: any }> {
return this.validateUserNameAvailableFactory(c.value);
}
validateUserNameAvailableFactory(username: string) {
return new Promise(resolve => {
this.usersService.getUserByName(username)
.subscribe(
data => {
resolve({
usernameAvailable: true
})
},
error => {
resolve(null);
})
})
}
}
This is now working. However, I now have an issue where the the control temporarily invalidates itself while the async validator is running.
Return for true should be:
{usernameAvailable: true}
or null for false.

Adding Validation to a Dynamically constructed form

Scenario
I am developing a savedialog which accepts any simple object with string, boolean and date fields. I've constructed a component which handels the construction of this, now I would like to dynamically add validation to the input fields which have been created.
I'm programming in TypeScript, using Angular2 and Also a framework called PrimeNG which is the Angular2 version of PrimeFaces.
My code at the moment
Html
<p-dialog #dialog header="{{dialogTitle}}" [(visible)]="isDisplayed" [responsive]="true" showEffect="fade"
[modal]="true" [closable]="false" [closeOnEscape]="false" [modal]="true" [width]="1000" [resizable]="false">
<form novalidate #form (ngSubmit)="save()">
<div class="ui-grid ui-grid-responsive ui-fluid" *ngIf="saveObject">
<div *ngFor="let i of rows" class="ui-grid-row">
<div class="ui-grid-col-6" *ngFor="let field of fields | slice:(i*itemsPerRow):(i+1)*itemsPerRow">
<div class="ui-grid-col-5 field-label">
<label for="attribute">{{field.key}}</label>
</div>
<div class="ui-grid-col-5">
<p-checkbox *ngIf="booleanFields.indexOf(field.key) !== -1" binary="true"
[(ngModel)]="saveObject[field.key]" name="{{field.key}}"
[ngClass]="{'error-border-class': field.key.errors && (field.key.dirty || field.key.touched)}"
[valueValidator]="field.key" [validateObject]="saveObject"></p-checkbox>
<p-calendar *ngIf="dateFields.indexOf(field.key) !== -1" [(ngModel)]="saveObject[field.key]"
name="{{field.key}}"
[ngClass]="{'error-border-class': field.key.errors && (field.key.dirty || field.key.touched)}"
dateFormat="dd/mm/yy" [showIcon]="true" [appendTo]="dialog"
[monthNavigator]="true"
[ngClass]="{'error-border-class': field.key.errors && (field.key.dirty || field.key.touched)}"
[valueValidator]="field.key"
[validateObject]="saveObject"></p-calendar>
<input *ngIf="(booleanFields.indexOf(field.key) === -1) && (dateFields.indexOf(field.key) === -1)"
pInputText id="attribute" [(ngModel)]="saveObject[field.key]" name="{{field.key}}"
[ngClass]="{'error-border-class': field.key.errors && (field.key.dirty || field.key.touched)}"
[valueValidator]="field.key" [validateObject]="saveObject"/>
</div>
</div>
</div>
</div>
</form>
<p-footer>
<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix">
<button label=" " type="button" pButton (click)="hideDialog(true)">
<i class="fa fa-times fa-fw" aria-hidden="true"></i>Sluit
</button>
<button label=" " type="submit" pButton (click)="hideDialog(false)" [disabled]="!form.valid">
<i class="fa fa-check fa-fw" aria-hidden="true"></i>Opslaan
</button>
</div>
</p-footer>
SaveDialogComponent
import { Component, Input, Output, OnChanges, EventEmitter } from '#angular/core';
import { FieldUtils } from '../utils/fieldUtils';
import { ValueListService } from '../value-list/value-list.service';
#Component({
moduleId: module.id,
selector: 'save-dialog',
templateUrl: 'savedialog.component.html',
styleUrls: ['savedialog.component.css']
})
export class SaveDialogComponent implements OnChanges {
#Input() dialogTitle:string;
#Input() isDisplayed:boolean;
#Input() saveObject:any;
#Input() unwantedFields:string[] = [];
#Input() booleanFields:string[] = [];
#Input() dateFields:string[] = [];
#Output() hide:EventEmitter<boolean> = new EventEmitter<boolean>();
#Output() result:EventEmitter<Object> = new EventEmitter<any>();
private fields:any[];
private itemsPerRow:number = 2;
private rows:any[];
ngOnChanges() {
this.fields = FieldUtils.getFieldsWithValues(this.saveObject, this.unwantedFields);
this.rows = Array.from(Array(Math.ceil(this.fields.length / this.itemsPerRow)).keys());
}
hideDialog(clearChanges:boolean) {
if(clearChanges){
this.resetObject()
}
this.isDisplayed = false;
this.hide.emit(this.isDisplayed);
}
save() {
this.result.emit(this.saveObject);
}
private resetObject() {
for(let field of this.fields) {
this.saveObject[field.key] = field.value;
}
}
private getDate(date:string):Date {
return new Date(date);
}
}
I'm Not including field utils since this it isn't that important, basically It extracts all the fields from an object, uses the booleanFields and dateFields to order the fields inorder to place all the fields of a same type next to one another.
ValidatorDirective
import { Directive, Input } from '#angular/core';
import { AbstractControl, ValidatorFn, Validator, NG_VALIDATORS, FormControl } from '#angular/forms';
#Directive({
selector: '[valueValidator][ngModel]',
providers: [
{provide: NG_VALIDATORS, useExisting: ValueValidatorDirective, multi: true}
]
})
export class ValueValidatorDirective implements Validator {
#Input('valueValidator') fieldName:string;
#Input() validateObject:any;
#Input() values:any[];
datumStartValidator:ValidatorFn;
datumEindValidator:ValidatorFn;
codeValidator:ValidatorFn;
naamValidator:ValidatorFn;
volgNrValidator:ValidatorFn;
validate(c:FormControl) {
this.instantiateFields();
switch (this.fieldName) {
case 'datumStart':
return this.datumStartValidator(c);
case 'datumEind':
return this.datumEindValidator(c);
case 'code':
return this.codeValidator(c);
case 'naam':
return this.naamValidator(c);
case 'volgnr':
return this.volgNrValidator(c);
default :
return {
error: {
valid: false
}
}
}
}
instantiateFields() {
this.datumStartValidator = validateStartDatum(this.validateObject['datumEind']);
this.datumEindValidator = validateEindDatum(this.validateObject['datumStart']);
this.codeValidator = validateCode();
this.naamValidator = validateNaam();
this.volgNrValidator = validateVolgNr(null);
}
}
//We'll need multiple validator-functions here. one for each field.
function validateStartDatum(datumEind:Date):ValidatorFn {
return (c:AbstractControl) => {
let startDatum:Date = c.value;
let isNotNull:boolean = startDatum !== null;
let isBeforeEind:boolean = false;
if (isNotNull) {
isBeforeEind = datumEind.getTime() > startDatum.getTime();
}
if (isNotNull && isBeforeEind) {
return null
} else {
return returnError();
}
}
}
function validateEindDatum(startDatum:Date):ValidatorFn {
return (c:AbstractControl) => {
let eindDatum:Date = c.value;
let isNotNull:boolean = eindDatum !== null;
let isBeforeEind:boolean = false;
if (isNotNull) {
isBeforeEind = eindDatum.getTime() > startDatum.getTime();
}
if (isNotNull && isBeforeEind) {
return null
} else {
return returnError();
}
}
}
function validateCode():ValidatorFn {
return (c:AbstractControl) => {
let code:string = c.value;
if (code !== null) {
return null;
} else {
return returnError();
}
}
}
function validateNaam():ValidatorFn {
return (c:AbstractControl) => {
let naam:string = c.value;
if (naam !== null) {
return null;
} else {
return returnError();
}
}
}
function validateVolgNr(volgnummers:string[]):ValidatorFn {
return (c:AbstractControl) => {
return returnError();
}
}
function returnError():any {
return {
error: {
valid: false
}
}
}
My problem
First of all I want to say thank you for reading this all the way, you're a champ! I know my code is not the most well writen beautiful code you've ever seen but I'm just trying to get it to work at the moment. The problem I have at the moment is that Validation happens but I can't seem to set the class using
[ngClass]="{'error-border-class': field.key.errors && (field.key.dirty || field.key.touched)}"
field.key is found no problem But I don't seem to be able to use that as reference to the dynamic name given to the input fields. field.key.errors is undefined which I guess is to be expected. But I haven't found how to fix this yet.
Secondly I think that the way I have It now I'm going to end up having trouble with the validation of the entire form (to disable the submit button)
<button label=" " type="submit" pButton (click)="hideDialog(false)" [disabled]="!form.valid">
Any Ideas on how to fix this are welcome, I'm open to all suggestions.

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;
}