Jasmine/Karma - Unit test for button enable in Angular 2 - javascript

I am not much aware of Jasmine/Karma unit testing, Here i am testing reactive form button. If two fields having input my button will enable, this is normal functionality of my form. while unit testing for this functionality i am getting error like "Failed: Cannot read property 'nativeElement' of null". If any one knows please help me.
Here is my form.
<div class="grid" >
<div [formGroup]="orderUnitForm" >
<div class="form-group" [hidden]="searhPanel">
<div class="layer-types__layer-1" >
<div class="bx--row">
<div class="bx--col-md-12 bx--col-xs-12">
<select id="select-menu" class="bx--text-input" formControlName="ruleSelection" name="ruleSelection" (change)="onChange($event.target.value)" >
<option selected>{{defaultSearch}}</option>
<option *ngFor="let rule of rules" [value]="rule.id" >{{rule.name}}</option>
</select>
</div>
</div>
<div class="bx--row">
<!-- <div class="form-group" [ngClass]="{'has-error': displayMessage.orderingUnit }"> -->
<div class="bx--col-md-2 bx--col-xs-12" align="right">
<label for="orderingUnit" class="bx--label">Ordering Unit</label>
</div>
<div class="bx--col-md-10 bx--col-xs-12">
<input type="text" id="orderingUnit" placeholder="Ordering Unit" class="bx--text-input"
formControlName="orderingUnit" name="orderingUnit"
[attr.title]="orderingUnitTip" [attr.data-invalid]="displayMessage.orderingUnit ? '' : null">
<div class="bx--form-requirement" *ngIf="displayMessage.orderingUnit" >{{ displayMessage.orderingUnit }} </div>
</div>
</div>
<div class="bx--row">
<div class="bx--col-md-2 bx--col-xs-12" align="right">
<label for="orderReferenceNumber" class="bx--label">Order Reference Number</label>
</div>
<div class="bx--col-md-10 bx--col-xs-12">
<input type="text" class=" bx--text-input" id="orderReferenceNumber" placeholder="Order Reference Number"
formControlName="orderReferenceNumber" name="orderReferenceNumber"
[attr.title]="orderReferenceNumberTip" [attr.data-invalid]="displayMessage.orderReferenceNumber ? '' : null">
<div class="bx--form-requirement" *ngIf="displayMessage.orderReferenceNumber" >{{ displayMessage.orderReferenceNumber }} </div>
</div>
</div>
<div class="bx--col-md-1 bx--col-xs-4" >
<!-- <carbon-button type="primary" (click)="onInclude()">Include</carbon-button> -->
<button class="bx--btn bx--btn--primary" type="button" id="inc" (click)="onInclude()" [disabled]="!valid || !orderUnitForm.valid">Include</button>
</div>
</div>
</div>
Here is my test cases:
describe('SearchPanelComponent', () => {
let component: SearchPanelComponent;
let fixture: ComponentFixture<SearchPanelComponent>;
let includeBtn: HTMLElement;
let orderingUnit: HTMLElement;
let orderReferenceNumber: HTMLElement;
let el: HTMLElement;
let overlayContainerElement: HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ReactiveFormsModule, FormsModule,CarbonDatepickerModule, CarbonIconModule, StoreModule.forRoot({})],
declarations: [ SearchPanelComponent, ModalComponent, UploadsearchcriteriaComponent, ],
providers: [Store,StoreModule,CustomerorderService, ApiConnectorService, HttpClient, HttpHandler,ModalService]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SearchPanelComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should check include is enabled after inputs combinations', async(() => {
includeBtn = fixture.debugElement.query(By.css('button')).nativeElement;
fixture.whenStable().then(() => {
var inputElement = <HTMLInputElement>document.getElementById('orderingUnit');
inputElement.value = 'abc';
inputElement.dispatchEvent(new Event('input'));
var inputElement1 = <HTMLInputElement>document.getElementById('orderReferenceNumber');
inputElement1.value = 'abcdef';
inputElement1.dispatchEvent(new Event('input'));
fixture.detectChanges();
expect(includeBtn.getAttribute('ng-reflect-enabled')).toBe('true', 'Include button enabled should now be true');
});
}));
});

Related

Pass input text value to function per click

I want to insert the value inserted into an input in the database using Angular as the frontend and php as the backend but I'm not able to insert the input value into the method along with the user.id.
The input is for the reason of moderation when clicking on disapprove it is necessary to pass the reason but it is not entering.
import { Component, OnInit, TemplateRef } from '#angular/core';
import { FormGroup } from '#angular/forms';
import { observerMixin } from '#rodrigowba/observer-component';
import { ResponseData, DefaultResponse } from '#rodrigowba/http-common';
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
import { ToastrService } from 'ngx-toastr';
import { Observable } from 'rxjs';
import { ActionPayload } from '~/ngrx';
import {
HotsiteUser,
HotsiteUsersFacade,
HotsiteUsersFormService,
RegistrationStatusTypes,
UpdateHotsiteUserRequest,
HotsitePointsPrebase,
} from '~/admin/users';
import {
updateHotsiteUser,
hotsiteUserUpdated,
hotsiteUserUpdateFailed,
hotsiteUserRegistrationModerated,
hotsiteUserModerateRegistrationFailed
} from '~/admin/users/state';
import { distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators';
#Component({
templateUrl: './view.component.html',
})
export class ViewComponent extends observerMixin() implements OnInit {
user$: Observable<HotsiteUser>;
pointsPrebase$: Observable<HotsitePointsPrebase[]>;
customFields$: Observable<{
field: string,
value: string
}[]>;
registrationStatusTypes = RegistrationStatusTypes;
form: FormGroup;
modalRef: BsModalRef;
submiting = false;
constructor(
private hotsiteUsersFacade: HotsiteUsersFacade,
private hotsiteUsersFormService: HotsiteUsersFormService,
private modalService: BsModalService,
private toastr: ToastrService
) {
super();
this.form = this.hotsiteUsersFormService.updateForm();
}
ngOnInit() {
this.user$ = this.hotsiteUsersFacade.selectCurrentHotsiteUser();
this.customFields$ = this.user$.pipe(
map(user => Object.values(user.custom_fields)),
map(customFields => customFields.map(customField => {
let value = customField.value;
if (Array.isArray(value)) {
value = value.join(', ');
}
return {
field: customField.field,
value
};
}))
);
this.pointsPrebase$ = this.user$.pipe(
map(user => user.id),
distinctUntilChanged(),
tap(id => {
this.hotsiteUsersFacade.fetchHotsitePointsPrebase(id);
}),
switchMap(id => this.hotsiteUsersFacade.selectHotsitePointsPrebaseByHotsiteUser(id))
);
this.observe(this.user$).subscribe(user => {
this.form.patchValue(user);
});
this.observe(
this.hotsiteUsersFacade.ofType(updateHotsiteUser)
).subscribe(() => {
this.submiting = true;
});
this.observe(
this.hotsiteUsersFacade.ofType<ActionPayload<ResponseData<HotsiteUser>>>(
hotsiteUserUpdated,
hotsiteUserRegistrationModerated
)
).subscribe(action => {
const { message, data } = action.payload;
this.submiting = false;
this.toastr.success(message);
});
this.observe(
this.hotsiteUsersFacade.ofType<ActionPayload<DefaultResponse>>(
hotsiteUserUpdateFailed,
hotsiteUserModerateRegistrationFailed
)
).subscribe(action => {
const { message } = action.payload;
this.submiting = false;
this.toastr.error(message);
});
}
onSubmit(id: string, data: UpdateHotsiteUserRequest) {
this.hotsiteUsersFacade.updateHotsiteUser(id, data);
}
openModal(template: TemplateRef<any>, size = 'modal-md') {
this.modalRef = this.modalService.show(template, { class: size });
}
approveRegistration(id: string,reason: string) {
this.hotsiteUsersFacade.moderateRegistrationHotsiteUser(id, { approved: true,reason });
}
rejectRegistration(id: string,reason: string) {
this.hotsiteUsersFacade.moderateRegistrationHotsiteUser(id, { approved: false,reason });
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<form [formGroup]="form" (ngSubmit)="onSubmit(user.id, form.value)" >
<form [formGroup]="form" (ngSubmit)="onSubmit(user.id, form.value)" >
<div class="row mb-3">
<div class="col-12">
<div class="form-group">
<label>Name</label>
<input type="text" [value]="user.name" class="form-control" readonly />
</div>
</div>
<div class="col-12 col-lg-6">
<div class="form-group">
<label>E-mail</label>
<input type="text" [value]="user.email" class="form-control" readonly />
</div>
</div>
<div class="col-12 col-lg-6">
<div class="form-group">
<label>Document</label>
<input type="text" [value]="user.document" class="form-control" readonly />
</div>
</div>
<div class="col-12" *ngFor="let customField of customFields$ | async">
<div class="form-group">
<label>{{ customField.field }}</label>
<input type="text" [value]="customField.value" class="form-control" readonly />
</div>
</div>
<div class="col-auto">
<div class="form-group">
<mat-slide-toggle formControlName="admin" color="primary" ></mat-slide-toggle>
<label class="ml-2">Admin</label>
</div>
</div>
<div class="col-auto">
<div class="form-group">
<mat-slide-toggle formControlName="active" color="primary" ></mat-slide-toggle>
<label class="ml-2">Active</label>
</div>
</div>
</div>
<ng-container *ngIf="pointsPrebase$ | async as pointsPrebase">
<div class="row mb-3" *ngIf="pointsPrebase.length > 0">
<div class="col-12">
<h4 class="font-16 font-weight-bold">Points</h4>
</div>
<div class="col-12 col-lg-6">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>Chave</th>
<th class="text-center">Points</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let points of pointsPrebase">
<td>{{ points.value }}</td>
<td class="text-center">{{ points.points }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</ng-container>
<div class="form-row">
<ng-container *ngIf="user.registration_status === registrationStatusTypes.AwaitingModeration">
<div class="col-auto">
<label>Reason</label>
<input type="text" name="reason" placeholder="Reason of moderation..." class="form-control"/>
</div>
<div class="col-auto">
<button
type="button"
class="btn btn-success"
(click)="approveRegistration(user.id,form.reason)"
>
<app-loading-label [loading]="submiting">Approved </app-loading-label>
</button>
</div>
<div class="col-auto">
<button
type="button"
class="btn btn-danger"
(click)="rejectRegistration(user.id,form.reason)"
>
<app-loading-label [loading]="submiting">Repproved </app-loading-label>
</button>
</div>
</ng-container>
<div class="col text-right">
<button
type="submit"
class="btn btn-orange"
[disabled]="form.invalid || submiting"
>
<app-loading-label [loading]="submiting">Salvar</app-loading-label>
</button>
</div>
</div>
</form>
Error:
Property 'reason' does not exist on type 'formGroup'
As user776686 suggested, there is a formControlName missing linked to "reason" field.
To get the field value in HTML you should access to the FormGroup controls:
(click)="approveRegistration(user.id, form.controls.reason.value)"
Also you can create a "get" property in TS code and then access to it in HTML:
get reason() {
return this.form.controls.reason.value;
}
(click)="approveRegistration(user.id, reason)"
BTW, a field can be accessed too through the "get" method of a FormGroup:
get reason() {
return this.form.get('reason').value;
}
It expects a control with the attribute formControlName="reason" which is not present here:
<input type="text" name="reason" placeholder="Reason of moderation..." class="form-control"/>
This might be a reason.
If that doesn't help, you my also want to look into the *ngIf condition here:
<ng-container *ngIf="user.registration_status === registrationStatusTypes.AwaitingModeration">

is there a way to add a textarea to function with a floating label in this case?

I have a simple for with 3 fields using vue.js, I am setting up "floating labels" on focus, as of now I have the inputs working nicely adding and removing class "active" as expected. When I try to add "textarea" my app is breaking and returning "cannot read value of null", is there a way to add the textarea as the inputs are setup?
html:
<form #submit.prevent="submitForm()">
<div class="form-group">
<div id="floatWrapper" class="float-wrapper">
<label for="floatField">Enter Your Name</label>
<input
id="floatField"
v-model="contact_name"
type="text"
class="form-control form-control--email"
#input="$v.contact_name.$touch"
/>
</div>
<p v-if="$v.contact_name.$dirty">
<span v-if="!$v.contact_name.required" class="form__alert">
Please enter your name.
</span>
</p>
<div id="floatWrapper" class="float-wrapper">
<label for="floatField">Enter Your Email</label>
<input
v-model="contact_email"
type="email"
class="form-control form-control--email"
/>
</div>
<p v-if="$v.contact_email.$dirty">
<span v-if="!$v.contact_email.required" class="form__alert">
Email is required.
</span>
<span v-if="!$v.contact_email.email" class="form__alert">
Please enter a valid email
</span>
</p>
<div id="floatWrapper" class="float-wrapper">
<label for="floatField">Enter Your Message</label>
<textarea
v-model="contact_message"
class="form-control form-control--textarea"
rows="5"
/>
</div>
<p v-if="$v.contact_message.$dirty">
<span
v-if="!$v.contact_message.required"
class="form__alert"
>
Message must be over 10 characters
</span>
</p>
</div>
<button
type="submit"
data-cursor="hover"
class="btn btn-primary"
>
Send Message
<font-awesome-icon far icon="arrow-right" />
</button>
</form>
js:
mounted() {
const labelFloating = (() => {
const isFocus = (e) => {
const target = e.target
target.parentNode.classList.add('active')
}
const isBlur = (e) => {
const target = e.target
if (!target.value) {
target.parentNode.classList.remove('active')
}
}
const bindEvents = (element) => {
const field = element.querySelector('input')
field.addEventListener('focus', isFocus)
field.addEventListener('blur', isBlur)
const text = element.querySelector('textarea')
text.addEventListener('focus', isFocus)
text.addEventListener('blur', isBlur)
}
const initialize = () => {
const floatWraps = document.querySelectorAll('.float-wrapper')
floatWraps.forEach((element) => {
if (element.querySelector('input').value) {
element.classList.add('active')
} if (element.querySelector('textarea').value) {
element.classList.add('active')
}
bindEvents(element)
})
}
return {
init,
}
})()
labelFloating.init()
},
The if (element.querySelector('input').value) { will throw that error because you're chaining .value off the selector, but it doesn't exist and returns null. try this instead:
const selector = element.querySelector('input') || element.querySelector('textarea')
if (selector && selector.value) {
element.classList.add('active')
bindEvents(element)
}
And use the same refactor for the bindEvents method:
const bindEvents = (element) => {
const field = element.querySelector('input') || element.querySelector('textrea')
field.addEventListener('focus', isFocus)
field.addEventListener('blur', isBlur)
}

how to fix the Error: Cannot find control with path in angular

here's the code from the list html
list.component.html
<div nz-row formArrayName="tasks">
<ng-container *ngFor="let tasks of getTasks(taskFormGroup);let i = index">
<div nz-col nzXXl="12">
<div nz-col nzSpan="8">
<label [textContent]="tasks?.value?.task?.name"></label>
</div>
<div nz-col nzSpan="8">
<nz-form-item>
<nz-form-control>
<nz-radio-group [formControlName]="tasks.get('failed')">
<label nz-radio nzValue="true">Passed</label>
<label nz-radio nzValue="false">Failed</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col nzSpan="8">
<nz-form-item>
<nz-form-control>
<textarea nz-input formControlName="remarks" placeholder="Placeholder" class="remarks-textarea"
type="text"></textarea>
</nz-form-control>
</nz-form-item>
</div>
</div>
</ng-container>
</div>
code from list typescript
list.component.ts
createTaskFormGroup() {
const list = this.store.selectSnapshot(ConfigurationState.get('collections'));
const formArray: any = [];
if (Array.isArray(list.checklists)) {
list.checklists.map((data: any) => {
data.tasks.forEach((task: any) => {
formArray.push({
failed: false,
remarks: '',
task: task
});
});
});
}
console.log(formArray, '+++');
return this.fb.group({
remarks: new FormControl(['', [Validators.required]]),
tasks: this.fb.array([formArray])
});
}
getTasks(form: any) {
return form.controls.tasks.controls;
}
how to fix the error ERROR Error: Cannot find control with path: 'tasks -> ' which is the <nz-radio-group [formControlName]="tasks.get('failed')"> and also for the textarea which cannot find control with path
the error was in nz-radio-group which the error is cannot find control with path:
Thanks in advance.
you have to wrap your ngFor inside an formArrayName
<div formArrayName="tasks">
<ng-container *ngFor="let tasks of getTasks(taskFormGroup);let i = index">
....
</div>

How to trigger 'disabled' attribute validation for button if form is invalid?

I am testing my angular application and have component, where I want to check if button gets disabled if form is invalid. But disabled attribute is not added. What I'm doing wrong?
I tried to create a mock form, but it not gets validated either.
Also tried to set natively into html and dispatch input event, doesn't work either:
it('submit button should be disabled if form is invalid', async() => {
const inputDe = fixture.debugElement.nativeElement.querySelector('input[name="amount"]');
const inputEl = inputDe.nativeElement;
inputDe.value = 'test';
inputDe.dispatchEvent(new Event('input'));
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('.btn-success').getAttribute('disabled')).toBeTruthy();
});
Here's my code:
shopping-edit.component.ts
#Component({
selector: "app-shopping-edit",
templateUrl: "./shopping-edit.component.html",
styleUrls: ["./shopping-edit.component.css"]
})
export class ShoppingEditComponent implements OnInit, OnDestroy {
#ViewChild('form') form: NgForm;
}
shopping-edit.component.html
<div class="row">
<div class="col-xs-12">
<form (ngSubmit)="onSubmit()" #form="ngForm">
<div class="row">
<div class="col-sm-5 form-group">
<label for="name">Name</label>
<input ngModel name="name" type="text" id="name" class="form-control" required>
</div>
<div class="col-sm-2 form-group">
<label for="amount">Amount</label>
<input ngModel name="amount" type="number" id="amount" class="form-control" required pattern="^[1-9]+[0-9]*$" >
</div>
</div>
<div class="row">
<div class="col-xs-12">
<button class="btn btn-success" type="submit" [disabled]="!form.valid">{{ editMode ? 'Update' : 'Add' }}</button>
</div>
</div>
</form>
shopping-edit.component.spec.ts
describe('ShoppingEdit component', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
FormsModule
],
declarations: [ShoppingEditComponent]
});
fixture = TestBed.createComponent(ShoppingEditComponent);
});
it('submit button should be disabled if form is invalid', async() => {
// const testForm = <NgForm>{
// valid: false
// };
setTimeout(() => {
fixture.debugElement.componentInstance.form.setValue({name: '', amount: 'a555'});
}, 1000);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('.btn-success').getAttribute('disabled')).toBeTruthy();
});
});
Any ideas?

Aurelia issue with setting element class based on obj.id === $parent.selectedId

I completed the contact-manager tut from Aurelia.io and am incorporating it into as task manager tut I'm putting together. The markup below sets the li class based on task.id === $parent.id.
task-list.html
<template>
<div class="task-list">
<ul class="list-group">
<li repeat.for="task of tasks" class="list-group-item ${task.id === $parent.selectedId ? 'active' : ''}">
<a route-href="route: tasks; params.bind: {id:task.id}" click.delegate="$parent.select(task)">
<h4 class="list-group-item-heading">${task.name}</h4>
<span class="list-group-item-text ">${task.due | dateFormat}</span>
<p class="list-group-item-text">${task.isCompleted}</p>
</a>
</li>
</ul>
</div>
task-list.js
#inject(WebAPI, EventAggregator)
export class TaskList {
constructor(api, ea) {
this.api = api;
this.tasks = [];
ea.subscribe(TaskViewed, x => this.select(x.task));
ea.subscribe(TaskUpdated, x => {
let id = x.task.id;
let task = this.tasks.find(x => x.id == id);
Object.assign(task, x.task);
});
}
created() {
this.api.getList().then( x => this.tasks = x);
}
select(task) {
this.selectedId = task.id;
return true;
}
}
If I edit the current task, represented by
task-detail.html
<template>
<require from="resources/attributes/DatePicker"></require>
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Edit Task Profile</h3>
</div>
<div class="panel-body">
<form role="form" class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">Name</label>
<div class="col-sm-10">
<input type="text" placeholder="name" class="form-control" value.bind="task.name">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Description</label>
<div class="col-sm-10">
<input type="text" placeholder="description" class="form-control" value.bind="task.description">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Due Date</label>
<div class="col-sm-10">
<div class="input-group date">
<input type="text" datepicker class="form-control" value.bind="task.due | dateFormat:'L'"><span class="input-group-addon"><i class="glyphicon glyphicon-th"></i></span>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Urgency</label>
<div class="col-sm-10">
<input type="range" min="1" max="5" step="1" class="form-control" value.bind="task.urgency">
</div>
</div>
</form>
</div>
</div>
<div class="button-bar">
<button class="btn btn-info" click.delegate="addTask(task)" >Add New</button>
<button class="btn btn-success" click.delegate="save()" disabled.bind="!canSave">Save Edit</button>
</div>
</template>
task-detail.js
#inject(WebAPI, EventAggregator, Utils, DialogService)
export class TaskDetail {
constructor(api, ea, utils, dialogService) {
this.api = api;
this.ea = ea;
this.utils = utils;
this.dialogService = dialogService;
}
activate(params, routeConfig) {
this.routeConfig = routeConfig;
return this.api.getTaskDetails(params.id).then(task => {
this.task = task;
this.routeConfig.navModel.setTitle(task.name);
this.originalTask = this.utils.copyObj(task);
this.ea.publish(new TaskViewed(task));
});
}
get canSave() {
return this.task.name && !this.api.isRequesting;
}
save() {
console.log(this.task);
this.api.saveTask(this.task).then(task => {
this.task = task;
this.routeConfig.navModel.setTitle(task.name);
this.originalTask = this.utils.copyObj(task);
this.ea.publish(new TaskUpdated(this.task));
});
}
canDeactivate() {
if (!this.utils.objEq(this.originalTask, this.task)) {
let result = confirm('You have unsaved changes. Are you sure you wish to leave?');
if (!result) {
this.ea.publish(new TaskViewed(this.task));
}
return result;
}
return true;
}
addTask(task) {
var original = this.utils.copyObj(task);
this.dialogService.open({viewModel: AddTask, model: this.utils.copyObj(this.task)})
.then(result => {
if (result.wasCancelled) {
this.task.name = original.title;
this.task.description = original.description;
}
});
}
}
If a value has changed, navigation away from the current task is not allowed, and that works -- that is, the contact-detail part of the UI doesn't change. However, the task <li>, that one tries to navigate to still gets the active class applied. That's not supposed to happen.
If I step along in dev tools, on the Aurelia.io contact-manager, I see that the active class is briefly applied to the list item, then it goes away.
from the contact-manager's contact-list.js This was run when clicking an <li> and no prior item selected.
select(contact) {
this.selectedId = contact.id;
console.log(contact);
return true;
}
This logs
Object {__observers__: Object}
Object {id: 2, firstName: "Clive", lastName: "Lewis", email: "lewis#inklings.com", phoneNumber: "867-5309"}
The same code on my task-manager's (obviously with "contact" replaced by task") task-list.js logs
Object {description: "Meeting With The Bobs", urgency: "5", __observers__: Object}
Object {id: 2, name: "Meeting", description: "Meeting With The Bobs", due: "2016-09-27T22:30:00.000Z", isCompleted: falseā€¦}
My first instinct is to say it's got something to do with this.selectedId = contact.id
this there would refer to what I assume is a function called select (looks like the function keyword is missing in your example?) or the global object (i.e. window)
select(contact) {
this.selectedId = contact.id;
console.log(contact);
return true;
}
Fixed it. It wasn't working because I had pushstate enabled. That clears things up. Thanks therealklanni.

Categories