Runtime Error Cannot read property 'element' of undefined in angular 2? - angularjs

I have created form builder validators that do a validation perfectly but i need get a error message from validators so i have tried some method that i shown below
import { Injectable,Output,Component} from '#angular/core';
import { FormGroup, FormControl} from '#angular/forms';
import{Sharedata} from '../providers/sharedata';
export class NextPayDayValidator1 {
public error: any="Next Pay Date should be greater than todays date";
constructor(public Share:Sharedata){
}
public isValid(control: FormControl): any {
// console.log("false");
let formGroup = control.parent;
var IsValid=true;
var errormessage;
// this.Err="eerere";
if(formGroup) {
console.log("true");
var SelVal_Howpaid=formGroup.get('Frequency').value;
console.log(SelVal_Howpaid);
var today = new Date();
var today_date = today.getDate();
var today_month = today.getMonth();
var today_year = today.getFullYear();
var weekNo = 0;
for (var index = week[0]; index <= week[1]; index++) {
weekNo++;
}
var nextpaydaycontrol=formGroup.get('NextPayDate');
var date_next = new Date( formGroup.get('NextPayDate').value);
var date_nextpaydate = date_next.getDate();
var month_nextpaydate = date_next.getMonth();
var year_nextpaydate = date_next.getFullYear();
console.log("nextpaydaycontrol"+date_next +"date"+date_nextpaydate+"month"+month_nextpaydate+"year"+year_nextpaydate);
if (nextpaydaycontrol.value == "") {
IsValid = false;
errormessage = "* Please select Next Pay Date";
console.log(errormessage);
this.error=errormessage;
alert(this.error);
return{
" * Please select Next Pay Date":true
}
}
}
}
my addleads.html
<ion-item>
<ion-label>Next Pay Date:</ion-label>
<!--<ion-input formControlName="NextPayDate" type="number"></ion-input>-->
<ion-datetime displayFormat="MM/DD/YYYY" formControlName="NextPayDate" (ionChange)="npay()"></ion-datetime>
</ion-item>
<span style="color:red" *ngIf="!RegisterForm3.controls.NextPayDate.valid && (!RegisterForm3.controls.NextPayDate.dirty || submitAttempt)">ddd </span>
<span style="color:red" *ngIf="!RegisterForm3.controls.NextPayDate.valid && RegisterForm3.controls.NextPayDate.hasError('Paymustgreaterthentodaydate') && (!RegisterForm3.controls.NextPayDate.dirty || submitAttempt)"> * Next Payday Must Be Greater Than Today's Date </span>
<span style="color:red" *ngIf="!RegisterForm3.controls.NextPayDate.valid && RegisterForm3.controls.NextPayDate.hasError('Invalid') && (!RegisterForm3.controls.NextPayDate.dirty || submitAttempt)"> * Invalid Next Payday</span>
<hr/>
and my addlead ts
import { Component} from '#angular/core';
import { NavController,Platform } from 'ionic-angular';
import {ViewChild} from '#angular/core';
import {Content} from 'ionic-angular';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import{Sharedata} from '../../providers/sharedata';
import {NextPayDayValidator1} from '../../validators/NextPayDate'
import 'rxjs/add/operator/map';
/*
Generated class for the AddLeads page.
See http://ionicframework.com/docs/v2/components/#navigation for more info on
Ionic pages and navigation.
*/
#Component({
templateUrl: 'add-leads.html'
})
export class AddLeadsPage {
RegisterForm3: FormGroup;
public NextPayDateErrorMsg:any;
loading: any;
constructor(public navCtrl: NavController,platform: Platform,public np:NextPayDayValidator1 ,private datePipe: DatePipe, public formBuilder: FormBuilder, public toastCtrl: ToastController,public loginservice :Loginservice,public sharedata:Sharedata, public loadingCtrl: LoadingController,
public http: Http, public alertCtrl: AlertController) {
this.NextPayDateErrorMsg=this.np.error;
alert(this.NextPayDateErrorMsg)
this.RegisterForm3 = formBuilder.group({
LastPayDate: ['', Validators.required],
NextPayDate:['',np.isValid]//here i invoke my validator
});
}
}
the above code i have create error global variable.if any error occurs assign errormsg to error global variable;if i trying to execute validation validation will fires error messge shown in alert after closing alert me getting a error like
EXCEPTION: Error in ./AddLeadsPage class AddLeadsPage - inline
template:427:65 caused by: Cannot set property 'error' of undefined
any one help me to fix this bugs

You have set a custom validator NextPayDayValidator1 as a component instead of a directive. A component cannot be injected like a provider.
Check here for custom validators.
#Directive({
selector: '[next-pay-valid]',
providers: [{provide: NG_VALIDATORS, useExisting: NextPayDayValidator1, multi: true}]
})
export class NextPayDayValidator1 implements Validator, OnChanges {..}
Or create a provider for NextPayDayValidator1
#Injectable()
export class NextPayDayValidator1 {
public error: any="Next Pay Date should be greater than todays date";
constructor(public Share:Sharedata){
}
public isValid(control: FormControl): any {
// console.log("false");
let formGroup = control.parent;
var IsValid=true;
//....
}
}
and inject in your component constructor.

Related

Angular 4 Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays

Here is the code below:
component.ts
by selecting match geting id in routing, then taking this id from URL
export class MatchComponent implements OnInit {
_postArrayMatch: match[];
constructor(public router:Router, private matchService: MatchService,
private route: ActivatedRoute) {}
ngOnInit(){
this.getMatchId();
}
getMatchId() :void {
this.route.params.forEach((params: Params)=> {
let id = +params['id'];
this.matchService.getMatch(id).subscribe(
resultArray => this._postArrayMatch = resultArray,
error => console.log("Error ::" + error))
})
}
component.html
just basic interpolation by doing ngFor loop
<div *ngFor="let post of _postArrayMatch">
<p>{{post.team1.name}}</p>
</div>
service.ts
passing the dynamic id
getMatch(id:number): Observable<match[]>{
return this.http.get<match[]>(`http://localhost:3000/match/${id}`)
}
interface
export interface match{
team1:{
name:string,
id:number
}
team2:{
name:string,
id:number
}
}
Try something like this where you create the object in your response
component.ts
export class MatchComponent implements OnInit {
_postArrayMatch: match[];
newArr: Array<Object> = [];
constructor(public router:Router, private matchService: MatchService,
private route: ActivatedRoute) {}
ngOnInit(){
this.getMatchId();
}
getMatchId() :void {
this.route.params.forEach((params: Params)=> {
let id = +params['id'];
this.matchService.getMatch(id).subscribe(
resultArray => {
this._postArrayMatch = resultArray;
const keys = Object.keys(this._postArrayMatch) // new stuff starts here
for(let i = 0; i < keys.length; i++) {
newArr.push(this._postArrayMatch[keys[i]]);
newArr[i]['team'] = keys[i];
}
},
error => console.log("Error ::" + error))
})
}
And then you can access ALL of your sub objects in your html
Component.html
<div *ngFor="let post of newArr">
<p> {{post.team}}: {{post.name}}</p>
</div>
Currently, with what you have you are hard coding for team 1, and if you want to do that then you shouldn't be using the *ngFor
Thats seems the easiest way i could find on how to get the data from objects.
<div *ngFor="let post of objectKeys(_postArrayMatch.team1)">
<div> Team1: {{ _postArrayMatch.team1[post]}}</div>
</div>
component.ts
objectKeys = Object.keys;

ionic 2 get ion-input text to refresh

I have a page with an ion-input in a FormGroup.
When they go to the page, data is loaded from a server. When the data comes in I want the ion-input to be filled in with the data from the server, which the user can then edit and save.
I cannot get the ion-input to show the data. (it remains blank)
Here is the page:
import { Component,ViewChild } from '#angular/core';
import { Validators, FormBuilder, FormGroup } from "#angular/forms";
import { NavController, App, MenuController, NavParams, AlertController,Content } from 'ionic-angular';
import {DomSanitizer,SafeResourceUrl} from '#angular/platform-browser';
import { TabsPage } from '../tabs/tabs';
// Providers
import { ProjectDetailService } from '../../providers/project-detail-service';
#Component({
selector: 'page-form',
templateUrl: 'form.html',
})
export class FormPage {
#ViewChild(Content) content: Content;
newObject: FormGroup;
object: any = {};
objectKey: string = "";
pageTitle: string = "Create New";
videoURL: SafeResourceUrl;
sanitizer: DomSanitizer;
updating: boolean = false;
constructor( public formBuilder: FormBuilder,
public service: ProjectDetailService,
public navParams: NavParams,
public app: App,
public alertCtrl: AlertController,
sanitizer: DomSanitizer ) {
this.sanitizer = sanitizer;
this.newObject = this.formBuilder.group({
name: this.object.name
});
}
setData()
{
this.newObject.value.name = this.object.name;
//none of these work:
//this.content.resize();
//window.location.reload();
//this.app.getRootNav().setRoot(this.app.getRootNav().getActive().component);
}
ionViewDidLoad()
{
this.objectKey = this.navParams.get('projectKey');
console.log("objectkey="+this.objectKey)
this.service.getProject(this.objectKey).subscribe( ( data: any ) => {
this.object = data;
this.setData();
})
}
This is the html:
<ion-content padding>
<form [formGroup]="newObject" (ngSubmit)="save()">
<ion-item>
<ion-label>Project Name</ion-label>
<ion-input type="text" formControlName="name"></ion-input>
</ion-item>
</form>
</ion-content>
I think FormBuilder is not a two way bindier Instead use a simple two way binding like this
<ion-input type="text" [(ngModel)]="name" formControlName="name"></ion-input>
and access as
this.name = 'something';

Refresh sortable when a new item is added to the array

Sortable component only shows initial array elements. When a new value is pushed into array, the sortable does not display it.
Component:
import { Component } from '#angular/core';
#Component({
selector: 'custom-item-template-demo',
templateUrl: './custom-item-template.html'
})
export class CustomItemTemplateDemoComponent {
public itemStringsLeft: any[] = [
'Windstorm',
'Bombasto',
'Magneta',
'Tornado'
];
public addItem() {
this.itemStringsLeft.push("new item");
}
}
Template:
<button type="button" (click)="addItem()">Add</button>
<template #itemTemplate let-item="item" let-index="index"><span>{{index}}: {{item.value}}</span></template>
{{itemStringsLeft.length}}
<pre>{{ itemStringsLeft | json }}</pre>
<bs-sortable
[(ngModel)]="itemStringsLeft"
[itemTemplate]="itemTemplate"
itemClass="sortable-item"
itemActiveClass="sortable-item-active"
placeholderItem="Drag here"
placeholderClass="placeholderStyle"
wrapperClass="sortable-wrapper"
></bs-sortable>
Workaround: Call manually to writeValue of the SortableComponent
import { Component, ViewChild } from '#angular/core';
#Component({
selector: 'custom-item-template-demo',
templateUrl: './custom-item-template.html'
})
export class CustomItemTemplateDemoComponent {
public itemStringsLeft: any[] = [
'Windstorm',
'Bombasto',
'Magneta',
'Tornado'
];
#ViewChild(SortableComponent, {static: false}) sortableComponent: SortableComponent;
public addItem() {
this.itemStringsLeft.push("new item");
this.sortableComponent.writeValue(this.itemStringsLeft);
}
}
Another workaround with re asigning list values:
public addItem() {
this.itemStringsLeft.push("new item");
this.itemStringsLeft = this.itemStringsLeft.slice();
}
should be add import { SortableComponent } from 'ngx-bootstrap';
It will working.
The spread operator worked well for me with this issue:
addItem(){
this.itemStringsLeft = [...this.itemStringsLeft, {name: 'Windstorm', range: 5}];
}

Ionic2 and AngularJS2 application using Typescript doesn't find type

I am trying to build an Ionic2 and AngularJS2 application using TypeScript, and I am getting the error: EXCEPTION: No provider for CalEvent!
// File event.ts
export class CalEvent {
name: string;
date: Date;
description: string;
isComplete: boolean;
constructor(n: string, d: Date){
this.name = n;
this.date= d;
}
toString(){
return this.name + ' at ' + this.date;
}
}
/*****************************/
// File event_card_large.ts
import {Component} from 'angular2/core'
import {CalEvent} from '../classes/event.ts';
#Component({
selector: 'event-card-large',
template: '<div style="color: red;">here</div>'
})
export class EventCardLarge{
constructor(public calEvent: CalEvent){}
}
/*****************************/
// File my_page.ts
import {Page} from 'ionic-angular';
import {CalEvent} from '../../classes/event.ts';
import {EventCardLarge} from '../../components/event_card_large.ts';
#Page({
templateUrl: 'build/pages/my_page/my_page.html',
directives:[EventCardLarge]
})
export class MyPage {
public pageName: string;
public testItems: CalEvent[];
selectedItem = 0;
constructor() {
// Test code
this.pageName = 'Test Page 2016-05-17';
this.testItems = [];
let d1 = new Date('2016-05-17');
let ce = new CalEvent('The name', d1);
ce.isComplete = true;
this.testItems.push();
}
}
/*****************************/
// File my_page.html
...
<ion-item *ngFor="#v of testItems; #i = index" >
<event-card-large [calEvent]="v">Loading...</event-card-large>
</ion-item>
...
Thanks for any help.
The problem is you are trying to inject CalEvent in EventCardLarge:
constructor(public calEvent: CalEvent){}
Just declare calEvent as a member of EventCardLarge:
export class EventCardLarge{
calEvent: CalEvent;
constructor(){}
}
It turned out that I needed to make the CalEvent class a "provider", and inject it in the EventCardLarge metadata.
#Component({
selector: 'event-card-large',
template: '<div style="color: red;">here</div>',
providers: [CalEvent]
})

AngularJS / Typescript - Directive with dynamic template loading and events

I've got the following directive (I've cut out the non-important part for the sake of brevity) :
I basically use the ng-include directive to dynamically load my templates.
Directive
module chat.directives {
"use strict";
export class ChatWindow implements ng.IDirective {
public restrict = 'E'
public static DirectoryName = "chatWindow";
public scope = {
chatModel: '=',
chatSection: '#chatSection'
}
public template(element : ng.IAugmentedJQuery, attrs : IChatWindowAtributes) {
return '<div ng-include="getTemplateUrl()"></div>';
}
public link(scope:chat.controllers.IChatScope, element:ng.IAugmentedJQuery, attrs:ng.IAttributes) {
scope.getTemplateUrl = () => {
return "/chat/directives/" + scope.chatSection + "-chat-window-template.html";
}
}
public static factory():ng.IDirectiveFactory {
var directive = () => new ChatWindow();
directive.$inject = [];
return directive;
}
}
interface IChatWindowAtributes extends ng.IAttributes {
chatSection : string;
}
angular
.module('chat')
.directive(chat.directives.ChatWindow.DirectoryName, chat.directives.ChatWindow.factory());
}
Problems do arise as soon as I try to implement an event in one of the templates, for example ng-click.
Because I am using the ng-include hack, element.html() of the linkage function refers to <div ng-include="getTemplateUrl()"></div> and thus doesn't allow me to setup an eventhandler programmatically.
HTML Template
<!-- Chat window-->
<div class="col-xs-4 chat-window">
<aside>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-list-alt icon"></span>
</div>
<div class="chat-output">
</div>
<form action="">
<input id="msgInput" autocomplete="off"/>
<button ng-click="chat.sendMessage('hi')" stop-event>Send</button>
</form>
</div>
</aside>
</div>
Additionally, any call from the template with ng-click="chat.sendMessage('hi')" doesn't trigger the corresponding function in my controller.
Controller Implementation
module chat.controllers {
'use strict';
class ChatCtrl {
public chatHistory : Array<Common.Services.IMessage> = [];
public chatSection : string;
public currentMessage : string;
// $inject annotation.
// It provides $injector with information about dependencies to be injected into constructor
// it is better to have it close to the constructor, because the parameters must match in count and type.
// See http://docs.angularjs.org/guide/di
public static $inject = [
'$scope',
'UserService',
'MessageService'
];
// dependencies are injected via AngularJS $injector
constructor(private $scope: IChatScope, private userService : User.Services.IUserService, private messageService : Common.Services.IMessageService) {
this.$scope.chatModel = {
chatHistory: this.chatHistory,
userService : this.userService,
messageService: this.messageService,
storeChatSectionInCtrl : this.storeChatSectionInCtrl,
subscribeToChatSectionEvents : this.subscribeToChatSectionEvents,
fetchChatHistory : this.fetchChatHistory
}
}
public storeChatSectionInCtrl(section){
// Store the section additionally to the directive in the controller
this.chatSection = section;
}
public subscribeToChatSectionEvents(section : string){
var self = this;
// Subscribe for the chat section for incoming messages
this.messageService.addMessageListener(section + "ChatMessage", function(){
});
// Subscribe for incoming messages to load the chat history
this.messageService.addMessageListener(section + "ChatHistory", function(message : ChatHistoryMessage){
self.chatHistory = message.data.chatHistory;
});
}
// Send a chat message to the server
public sendMessage(message : string){
var messageObj = new ChatInputMessage({
chatSectionPrefix : this.chatSection,
chatMessageObj : new ChatMessage({
message : message
})
});
this.messageService.sendMessage(messageObj);
}
// Send a request for the chat history to the server
public fetchChatHistory(section : string){
var messageObj : ChatHistoryMessage = new ChatHistoryMessage({
chatSectionPrefix : section,
chatHistory : null
});
// Send a request in order to retrieve the chat history of the given section
this.messageService.sendMessage(messageObj);
}
}
export interface IChatScope extends ng.IScope {
getTemplateUrl : () => string;
chatModel : IChatModel;
chatSection : string;
}
export interface IChatModel {
chatHistory : Array<Common.Services.IMessage>;
userService: User.Services.IUserService;
messageService : Common.Services.IMessageService;
storeChatSectionInCtrl : (section : string) => void;
subscribeToChatSectionEvents: (nameOfEventListener : string) => void;
fetchChatHistory : (section: string) => void;
}
// Message
export interface IChatMessage {
message : string;
creationDate? : string;
from? : string;
to? : string;
}
export class ChatMessage implements IChatMessage {
public message : string;
public creationDate : string;
public from : string;
public to : string;
constructor(message : IChatMessage){
this.message = message.message;
this.creationDate = message.creationDate;
this.from = message.from;
this.to = message.to;
}
};
// Message Service
export interface IChatData{
chatSectionPrefix : string;
chatMessageObj : IChatMessage;
}
export class ChatInputMessage extends Common.Services.ClientMessage<IChatData> {
static NAME = "ChatMessage";
constructor (chatData: IChatData) {
super(chatData.chatSectionPrefix + ChatInputMessage.NAME, chatData);
}
}
// Chat history
export class ChatHistoryMessage extends Common.Services.ClientMessage<IChatHistory> {
static NAME = "ChatHistory";
constructor (chatData: IChatHistory) {
super(chatData.chatSectionPrefix + ChatHistoryMessage.NAME, chatData);
}
}
export interface IChatHistory{
chatSectionPrefix : string;
chatHistory : Array<IChatMessage>;
}
/**
* #ngdoc object
* #name chat.controller:ChatCtrl
*
* #description
*
*/
angular
.module('chat')
.controller('ChatCtrl', ChatCtrl);
}
HTML
<div ng-controller="ChatCtrl">
<chat-window chat-model="chatModel" chat-section='lobby'></chat-window>
</div>
Solution
For some reason I though I would operate on the controller instead of the directive - thus using sendMessage('hi') instead of chat.sendMessage('hi') solved the issue ...

Resources