I am quite a noob in Angular2 and typescript.
I want to pass a method from other class in a other file.
This is the file iam talking about in specific i want to pass the method deleteCondition():
export class ConditionBuilderComponent implements OnInit {
conditions: Condition[] = [];
catalog: Condition[] = [];
constructor(private _conditionService: ConditionService) { }
getConditions() {
this._conditionService.getConditions().then(conditions => this.catalog = conditions);
}
ngOnInit() {
this.getConditions();
}
onChange(conditionsIndex, catalogIndex) {
//console.log(selectedCondition);
//console.log(conditionsIndex);
console.log(catalogIndex);
this.conditions[conditionsIndex] = this.catalog[catalogIndex];
}
newCondition() {
this.conditions.push(this.catalog[0]);
}
deleteCondition() {
this.conditions.pop();
}
}
I want to pass the deleteCondition() method to an other file because in the other file this.conditions.pop() is not recognised of course.
First it was like this: https://www.dropbox.com/s/92z2oe7f4w5x2b5/conditions.jpg?dl=0
Here it deletes the last created but i want to delete each condition separately like this:
https://www.dropbox.com/s/ptwq6sk6da4p21k/new.jpg?dl=0
This is the code from the SelectCondition:
import {Component} from 'angular2/core';
import {Condition} from './condition';
import {ConditionBuilderComponent} from "./conditionbuilder.component";
#Component({
selector: 'select-condition',
template: `
<div class="col-xs-3">
<div class="form-group">
<select class="form-control" [(ngModel)]="selectedOperator">
<option *ngFor="#operator of selectOperators">{{operator}}</option>
</select>
</div>
</div>
<div class="col-xs-3">
<div class="form-group">
<div class="input-group">
<span class="btn-file">
<input type="file" (click)="selectFile()" multiple />
</span>
<input type="text" [(ngModel)]="fileValue" class="form-control" readonly>
<span class="input-group-addon">
<span class="glyphicon glyphicon-folder-open"></span>
</span>
</div>
</div>
</div>
<a class="btn btn-danger pull-right" (click)="deleteCondition()"><i class="glyphicon glyphicon-minus"></i></a>
`
})
export class SelectCondition extends Condition {
public name: string = 'select';
public fileValue: string;
public selectedOperator: string = 'in';
public selectOperators: Condition[] = [
"in"
];
selectFile() {
$(document).on('change', '.btn-file :file', function() {
var input = $(this),
numFiles = input.get(0).files ? input.get(0).files.length : 1,
label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
input.trigger('fileselect', [numFiles, label]);
});
$('.btn-file :file').on('fileselect', function(event, numFiles, label) {
var input = $(this).parents('.input-group').find(':text'),
log = numFiles > 1 ? numFiles + ' files selected' : label;
if( input.length ) {
input.val(log);
console.log(input.val());
}
});
}
deleteCondition = () => this.deleteCondition();
}
Please help me out.
Related
I am creating google autocomplete address form for multiple input fields. My code is work for single field. now i am changing function so it works for all location. how to avoid repeation of functions in above code for mulitple inputfield? I want to create this address functionality for multiple input box. https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform i am refer this plz need help
<div class="col-12 mb-3">
<label for="current-location" class="mb-1">Current Location</label>
<input type="text" name="locality" id="locality" class="form-control loc">
</div>
<div class="col-12 mb-3">
<label for="preferred-location" class="mb-1">Preferred Location </label>
<div class="row" id="location_row">
<div class="col-12 mb-2">
<input type="text" name="preferred_location[]" id="preferred_location_1" class="form-control loc" placeholder="Search & Select Location">
</div>
<div class="col-12 mb-2">
<input type="text" name="preferred_location[]" id="preferred_location_2" class="form-control loc" placeholder="Search & Select Location">
</div>
</div>
</div>
<script>
let autocomplete;
let address1Field;
let address2Field;
let postalField;
let inputField ;
function initAutocomplete() {
address1Field = document.querySelector("#locality");
address2Field = document.querySelector("#preferred_location_1");
autocomplete = new google.maps.places.Autocomplete(address1Field, {
componentRestrictions: { country: ["in"] },
fields: ["address_components", "geometry"],
types: ["address"],
});
autocomplete.addListener("place_changed", fillInAddress);
autocomplete2 = new google.maps.places.Autocomplete(address2Field, {
componentRestrictions: { country: ["in"] },
fields: ["address_components", "geometry"],
types: ["address"],
});
autocomplete2.addListener("place_changed", fillInAddress2);
}
function fillInAddress() {
const place = autocomplete.getPlace();
if(place!=undefined) {
for (const component of place.address_components) {
const componentType = component.types[0];
switch (componentType) {
case "locality":
document.querySelector("#locality").value = component.long_name;
break;
}
}
}
}
function fillInAddress2() {
const place = autocomplete2.getPlace();
if(place!=undefined) {
for (const component of place.address_components) {
const componentType = component.types[0];
switch (componentType) {
case "locality":
document.querySelector("#preferred_location_1").value = component.long_name;
break;
}
}
}
}
</script>
I have followed
the following guide
Angular-Reactive forms
I modified a bit the code to put it in a module, adding some fields to the originals model and it worked.
after upgrading to angular 8, the module is still working, but the console in Chrome for every control gives me this error:core.js:6150 ERROR Error: No value accessor for form control with name: 'title' at _throwError (forms.js:2603) at setUpControl (forms.js:2377) at FormGroupDirective.addControl (forms.js:5699) at FormControlName._setUpControl (forms.js:6274) at FormControlName.ngOnChanges (forms.js:6219) at FormControlName.rememberChangeHistoryAndInvokeOnChangesHook (core.js:1506) at callHook (core.js:2525) at callHooks (core.js:2492) at executeInitAndCheckHooks (core.js:2443) at selectIndexInternal (core.js:8389)
this is my code for question-form-component.html:
<div [formGroup]="form">
<label [attr.for]="question?.key">{{ question?.label }}</label>
<div [ngSwitch]="question?.controlType">
<input
ngDefaultControl
*ngSwitchCase="'textbox'"
[formControlName]="question?.key"
[id]="question?.key"
[type]="question?.type"
[value] = "question?.value"
/>
<div [ngSwitch]="question?.controlType">
<ion-textarea
ngDefaultControl
*ngSwitchCase="'textArea'"
[formControlName]="question?.key"
[id]="question?.key"
autoGrow="question?.autoGrow"
[value]= "question?.value"
></ion-textarea>
</div>
<div *ngSwitchCase="'barcodeScanner'">
<app-barcode-scanner
[formControlName]="question?.key"
(ngModelChange)="question?.onChange($event)"
[id]="question?.key"
[value]="question?.value"
></app-barcode-scanner>
</div>
<div *ngSwitchCase="'datebox'">
<ion-datetime [formControlName]="question?.key" [id]="question?.key">
</ion-datetime>
</div>
<div *ngSwitchCase="'switchBox'">
<p class="switchText">
{{ getValue ? question.labelTrue : question.labelFalse }}
</p>
<ion-icon
[name]="getValue ? question.iconTrue:question.iconFalse"
></ion-icon>
<ion-toggle
[formControlName]="question?.key"
[id]="question?.key"
></ion-toggle>
</div>
<div
[formControlName]="question?.key"
[id]="question?.key"
>
<div *ngSwitchCase="'itemSelector'"
[formControlName]="question?.key"
[id]="question?.key"
ngDefaultControl
>
<app-selector-items
[formControlName]="question?.key"
[id]="question?.key"
[text]="question?.text" [service]="question?.service" (selectedItem)="question.selectedItem($event)"
[sorterFunction]="question?.sorterFunction"
[filterFunction]="question?.ItemsFilterFunction"
[createPopup]= "question?.createPopup"
[item]="question?.value"
(selectedItem)="question.selectedItem($event)" >
</div>
<select
[id]="question?.key"
*ngSwitchCase="'dropdown'"
[value]="question?.value"
[formControlName]="question?.key"
>
<option *ngFor="let opt of question?.options" [value]="opt?.value">{{
opt.key
}}</option>
</select>
<div *ngSwitchCase="'geobox'">
<input-geolocation
[id]="question?.key"
[address]="question.value?.adress"
[formControlName]="question?.key"
(ngModelChange)="question?.onChange($event)"
></input-geolocation>
</div>
{{ question ? question.label : "" }} is required
this is my question-form-component.ts:
import {
Component,
Input,
OnInit,
Output,
EventEmitter,
ChangeDetectionStrategy,
ɵConsole,
OnChanges,
SimpleChanges
} from '#angular/core';
import { FormGroup, FormControl } from '#angular/forms';
import { QuestionBase } from '../../models/question-base';
#Component({
selector: 'app-question',
templateUrl: './question-form-component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class QuestionFormComponent implements OnInit, OnChanges {
public value: any;
#Input() question: QuestionBase;
#Input() form: FormGroup;
ngOnInit() {
this.value = this.question ? this.question.value : undefined;
this.form = this.form
? this.form
: new FormGroup({
// I need an instance of formgroup for run the tests
name: new FormControl(this.question.key),
value: new FormControl(this.question.value)
});
}
ngOnChanges(changes: SimpleChanges) {
}
get isValid() {
return this.question ? this.form.controls[this.question.key].valid : false;
}
get getValue() {
return this.question.key ? this.form.get(this.question.key).value : '';
}
getIcon() {
return this.form.get(this.question.key).value ? String(this.question.iconTrue) : String(this.question.iconFalse)
}
}
thanks in advance
I am making a simple website that has a feature to upload images. I tried it Laravel way which I made it in blade template and it works fine. Now I am trying to make it inside Vue Components
Here's my Create.vue
<template>
<div>
<div class="row">
<input type="hidden" name="_token" :value="csrf">
<div class="col-md-5">
<div class="detail-container">
<label for="title">Book Title:</label>
<input type="text" name="title" id="title" v-model="book_title" class="form-control">
</div>
<div class="detail-container">
<label for="title">Book Description:</label>
<textarea type="text" name="description" id="description" v-model="book_description" class="form-control" rows="5"></textarea>
</div>
<div class="detail-container">
<label for="title">Tags:</label>
<multiselect v-model="tags" :show-labels="false" name="selected_tags" :hide-selected="true" tag-placeholder="Add this as new tag" placeholder="Search or add a tag" label="name" track-by="id" :options="tagsObject" :multiple="true" :taggable="true" #tag="addTag" #input="selectTags">
<template slot="selection" slot-scope="tags"></template>
</multiselect>
</div>
</div>
<div class="col-md-7">
<!-- BOOK COVER WILL GO HERE -->
<div class="detail-container">
<label>Book Cover:</label>
<input type="file" class="form-control-file" id="book_cover" name="selected_cover" #change="onFileChange">
<small id="fileHelp" class="form-text text-muted">After you select your desired cover, it will show the preview of the photo below.</small>
<div id="preview">
<img v-if="url" :src="url" height="281" width="180" />
</div>
</div>
</div>
<div class="detail-container" style="margin-top: 20px;">
<button class="btn btn-primary" #click="saveBook()">Next</button>
</div>
</div>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
// register globally
Vue.component('multiselect', Multiselect)
export default {
// OR register locally
components: { Multiselect },
data () {
return {
csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
url: null,
selected_cover: null,
tags: [],
tagsObject: [],
selected_tags: [],
book_title: '',
book_description: ''
}
},
methods: {
getTags() {
let vm = this;
axios.get('/admin/getTags').then(function(result){
let data = result.data;
for(let i in data) {
vm.tagsObject.push({id: data[i].id, name: data[i].name});
}
});
},
addTag (newTag) {
const tag = {
name: newTag,
id: newTag.substring(0, 2) + Math.floor((Math.random() * 10000000))
}
this.tagsObject.push(tag);
this.tags.push(tag);
},
selectTags(value) {
this.selected_tags = value.map(a=>a.id);
},
onFileChange(e) {
const file = e.target.files[0];
this.url = URL.createObjectURL(file);
this.selected_cover = file;
},
saveBook() {
const fd = new FormData();
fd.append('image', this.selected_cover, this.selected_cover.name)
console.log(this.selected_cover);
var book_details = {
'title': this.book_title,
'description': this.book_description,
'book_cover': this.selected_cover,
'tags': this.selected_tags
};
axios.post('/admin/saveBook', book_details).then(function(result){
console.log('done')
})
}
},
created() {
this.getTags();
}
}
</script>
<!-- New step!
Add Multiselect CSS. Can be added as a static asset or inside a component. -->
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
and here's my controller
public function store(Request $request)
{
$this->validate(request(), [
'title' => 'required|min:5',
'description' => 'required|min:10',
'book_cover' => 'required|image|mimes:jpeg,jpg,png|max:10000'
]);
// File Upload
if($request->hasFile('book_cover')) {
$fileNameWithExt = $request->file('book_cover')->getClientOriginalName();
// GET FILE NAME
$filename = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
// GET EXTENSION
$extension = $request->file('book_cover')->getClientOriginalExtension();
// File Unique Name
$fileNameToStore = $filename. '_'. time().'.'.$extension;
$path = $request->file('book_cover')->storeAs('public/book_covers', $fileNameToStore);
} else {
$fileNameToStore = 'noimage.jpg';
}
$book = new Book;
$book->title = request('title');
$book->description = request('description');
$book->book_cover = $fileNameToStore;
$book->save();
$book->tags()->sync($request->tags, false);
return back()->with('success', 'Book Created Successfully!');
}
I never touched my controller because this is what I used when I do this feature in Laravel Way but when I save it, the details are being saved but the image is not uploading instead it saves noimage.jpg in the database. Does anyone know what I am doing wrong?
i tried to add this part const fd = new FormData(); in book_details but when i console.log(fd) it returned no data.
you should pass the fd object and not the book_details in your POST request.
you could do it something like this.
onFileChange(e) {
const file = e.target.files[0];
// this.url = URL.createObjectURL(file);
this.selected_cover = file;
},
saveBook() {
const fd = new FormData();
fd.append('image', this.selected_cover)
fd.append('title', this.book_title)
fd.append('description', this.book_description)
fd.append('book_cover', URL.createObjectURL(this.selected_cover))
fd.append('tags', this.selected_tags)
axios.post('/admin/saveBook', fd).then(function(result){
console.log('done')
})
}
and also, you can't just console.log the fd in the console. what you can do instead is something like this
for (var pair of fd.entries()) {
console.log(pair[0]+ ', ' + pair[1]);
}
FormData is a special type of object which is not stringifyable and cannot just be printed out using console.log. (link)
I have been unable to get the validation to work on an edit model-view that has data bound to it in the activate method of its view-model.
I have a created.ts which works on an object with the same fields. This file has almost the same code - the exception is that since this one is a create, no data needs to be loaded to it. In this case, the validation is working properly.
If I comment the code that loads the data for the edit model-view - in the activate method - the validation works properly.
Needless to say I am new to SPA, Aurelia and TypeScript and need some help!!
Below is the code in edit.ts
import { ContactRepository } from "./contactRepository";
import { autoinject } from "aurelia-framework";
import { ContactForEditDto } from "./contactForEditDto";
import { json } from "aurelia-fetch-client";
import { inject, NewInstance } from "aurelia-dependency-injection";
import { ValidationRules, ValidationControllerFactory, validateTrigger,
Validator } from "aurelia-validation";
#autoinject
export class Edit {
public saveStatusMessage: string;
public isSaved: number = -1;
private controller = null;
private validator = null;
public canSave: boolean = false;
constructor(public contactForEdit: ContactForEditDto, private repository:
ContactRepository, private controllerFactory: ValidationControllerFactory,
public contactFullName: string, validator: Validator) {
console.log("starting edit controller");
this.controller = controllerFactory.createForCurrentScope(validator);
this.controller.validateTrigger = validateTrigger.changeOrBlur;
this.validator = validator;
this.controller.subscribe(event => this.validateWhole());
ValidationRules
.ensure((c: ContactForEditDto) => c.contactFirstName)
.displayName("First Name")
.required().withMessage("\${$displayName} cannot be empty.")
.maxLength(50).withMessage("\${$displayName} cannot have more than 50 characters.")
.ensure((c: ContactForEditDto) => c.contactLastName)
.displayName("Last Name")
.required().withMessage("\${$displayName} cannot be empty.")
.maxLength(50).withMessage("\${$displayName} cannot have more than 50 characters.")
.ensure((c: ContactForEditDto) => c.contactEmailAddress)
.displayName("Email Address")
//.required().withMessage("\${$displayName} cannot be empty.")
.email().withMessage("\${$displayName} needs to be in a correct email address format.")
.maxLength(50).withMessage("\${$displayName} cannot have more than 50 characters.")
.ensure((c: ContactForEditDto) => c.contactPhoneNumber)
.displayName("Phone Number")
.required().withMessage("\${$displayName} cannot be empty.")
.maxLength(12).withMessage("\${$displayName} cannot have more than 12 characters.")
.matches(/\d{3}-\d{3}-\d{4}/).withMessage("'${$value}' is not a valid \${$displayName}. Please enter a phone in the format xxx-xxx-xxxx")
.on(ContactForEditDto);
}
// source https://www.jujens.eu/posts/en/2017/Jan/24/aurelia-validation/
workaround 3
validateWhole() {
this.validator.validateObject(this.contactForEdit)
.then(results => this.canSave = results.every(result => result.valid));
}
// Returning data from here because I can return a promise
// and let the router know when i have retrieved my initial data.
// Activate receives a params object as defined in the route.
activate(params) {
console.log("ACTIVATE ON EDIT PARAMS:" + params);
this.repository
.getById(params.id)
.then(data => {
console.log(data);
this.contactForEdit = data;
this.contactFullName = this.contactForEdit.contactLastName + ", " +
this.contactForEdit.contactFirstName; // This needs to come from a method
in
contact.
});
}
edit() {
this.saveStatusMessage = "";
this.isSaved = -1;
// This will be an edit
if (this.contactForEdit.contactId >= 1) {
this.repository
.update(this.contactForEdit)
.then(response => {
if (((response.status == 201) || (response.status == 204))
&& (response.ok == true)) {
this.isSaved = 1;
this.saveStatusMessage = "Successfully saved the contact";
}
else {
this.isSaved = 0;
//response.json().then(json => this.retVal = json);
//TODO: get more details about the error.
if (response.status == 400) {
this.saveStatusMessage = "Unable to save the contact. Please make sure that you entered correct values for every field and try again.";
}
else {
this.saveStatusMessage = "Unable to save the contact.";
}
}
});
}
}
clearContactFields() {
this.contactForEdit = new ContactForEditDto(-1, "", "", "", "");
}
}
Below is the code in edit.html
<template>
<form id="editContact" submit.delegate="edit()">
<!-- placeholder for status messages. If equal to 1 display it. If equals to
-1 or 1 hide this.-->
<div id="successStatusMessage" class.bind="isSaved == 1 ? 'visible' :
'hidden'">
<div id="divSuccessMessage" class="alert alert-success">
×
<!--<span class="glyphicon glyphicon glyphicon-ok" aria-hidden="true">
</span> TODO: How to get the glyphicon working? -->
<span class="sr-only"> Success:</span> ${saveStatusMessage}
</div>
</div>
<!-- placeholder for status messages. If equal to 0 is in error, so dislay error message. if equals to -1 or 1 hide this.-->
<div id="errorStatusMessage" class.bind="isSaved == 0 ? 'visible' : 'hidden'">
<!-- placeholder for status messages. -->
<div id="divErrorMessage" class="alert alert-danger">
×
<!-- <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> TODO: class="glyphicon glyphicon-exclamation-sign" how to get these in here for class? -->
<span class="sr-only"> Error:</span> ${saveStatusMessage}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
<!--<div if.bind="isCreate">
"Create a Contact"
</div>
<div if.bind="!isCreate">
Edit ${contactForEdit.contactFirstName}
</div>-->
${ "Edit " + contactFullName }
</div>
</div>
<div class="panel-body">
<div class="form-horizontal">
<div class="form-group" validation-errors.bind="editFirstNameErrors"
class.bind="editFirstNameErrors.length ? 'has-error' : ''">
<label class="control-label col-md-2">First Name: </label>
<div class="col-md-10">
<input type="text"
placeholder="First Name"
class="form-control"
value.bind="contactForEdit.contactFirstName & validate" required /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editFirstNameErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<div class="form-group" validation-errors.bind="editLastNameErrors"
class.bind="editLastNameErrors.length ? 'has-error' : ''">
<label class="control-label col-md-2">Last Name: </label>
<div class="col-md-10">
<input type="text"
placeholder="Last Name"
class="form-control"
value.bind="contactForEdit.contactLastName & validate" required /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editLastNameErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<div class="form-group" validation-errors.bind="emailErrors"
class.bind="editEmailErrors.length ? 'has-error' : ''">
<label for="emailAddress" class="control-label col-md-2">Email: </label>
<div class="col-md-10">
<input id="emailAddress"
type="text"
placeholder="Email Address (format: email#domain.com)"
class="form-control"
value.bind="contactForEdit.contactEmailAddress & validate" /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editEmailErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<div class="form-group" validation-errors.bind="editPhoneErrors"
class.bind="editPhoneErrors.length ? 'has-error' : ''">
<label class="control-label col-md-2">Phone: </label>
<div class="col-md-10">
<input type="text"
placeholder="Phone Number (format: xxx-xxx-xxxx)"
class="form-control"
value.bind="contactForEdit.contactPhoneNumber & validate" required /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editPhoneErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<button type="submit" class="btn btn-default ${canSave ? '' : 'disabled'}">
<!-- Look at click.dependent when there are child with buttons calling this.-->
Save
</button>
<!-- AA-10-17-17 - replaced with errors per input field. <ul for.bind="controller.errors">
<li repeat.for="error of controller.errors" style="color:red">
${error.message}
</li>
</ul>-->
</div>
</div>
</div>
</form>
<div>
<a route-href="route: home"
class="btn btn-default">
Back to list
</a>
</div>
</template>
I expect it's because of this code:
.getById(params.id)
.then(data => {
console.log(data);
this.contactForEdit = data;
your validation is against a ContactForEditDto object, but my guess is your repository is returning a JSON object cast to a ContactForEditDto, so it's not actually a class at all.
Try something like
console.log(data);
this.contactForEdit = new ContactForEditDto(data.id, data.firstname ..etc..);
or
console.log(data);
this.contactForEdit = Object.assign(new ContactForEditDto(), data);
We just had a similar problem and solved it by setting up our validations after assigning the remote data to our local field. In your code, you'd set up your validation rules after this.contactForEdit = data;
I am trying to update the items in my dropdown as my state updates with players BUT I am failing. Please help.
In the child component I have dropdown in the Skylight dialog box.
I am using following code which prints the dropdown of the array of players from the state. State is updated from the json.php (remote server).
<select name="bowlerId" value={this.state.bowlerId} onChange={this.handleInputChange} className="form-control">
<option value="">Select an existing bowler</option>
{
this.currState.teamBowling.players.map(function (player, index) {
return <option value="{player}" key={index}>{player}</option>
})
}
</select>
I can clearly see in the console.log that the state is correctly updated and it prints 11 player names. But in the child component it does not update the dropdown.
Surprising enough, in the child component componentWillReceiveProps() does print new player names as they become availble but the dropdown is not updated still.
Please advise.
Console.log output as page loads
BowlingSummary render() Object {id: 0, name: "", runs: 0, overs: 0, balls: 0…}
PropStore Object {id: 0, name: "", runs: 0, overs: 0, balls: 0…}
BowlingAddBowler render() []
Console.log output after few seconds as data is fetched from php
BowlingSummary render() Object {id: 20, name: "Team Bowling", runs: 0, overs: 0, balls: 0…}
componentWillReceiveProps Object {id: 20, name: "Team Bowling", runs: 0, overs: 0, balls: 0…}
BowlingAddBowler render() []
Parent component named BowlingSummary
class BowlingSummary extends Component {
render() {
const { store } = this.context;
const currState = store.getState();
this.isBowlerBowling = false;
console.log('BowlingSummary render()', currState.teamBowling);
return (
<div>
<div className="score-summary-bar">
<div className="row">
<div className="col-xs-4">Bowling</div>
<div className="col-xs-1"></div>
<div className="col-xs-1">Ovr</div>
<div className="col-xs-1">Mdn</div>
<div className="col-xs-1">Run</div>
<div className="col-xs-1">Wkt</div>
<div className="col-xs-1">Econ</div>
<div className="col-xs-1">W</div>
<div className="col-xs-1">N</div>
</div>
</div>
<div className="score-summary-bowling">
<div className="">
{
currState.teamBowling.players.map(function (player, index) {
if ( player.isBowling === true ) {
this.isBowlerBowling = true;
return <BowlingBowler player={player} key={index}/>
}
})
}
</div>
<div className="">
{
this.isBowlerBowling != true &&
<BowlingAddBowler propStore={store} />
}
</div>
</div>
<div className="score-summary-bowling">
<ScoreThisOver />
</div>
</div>
);
}
}
BowlingSummary.contextTypes = {
store: PropTypes.object
}
export default BowlingSummary;
Child component named BowlingAddBowler
class BowlingAddBowler extends Component {
constructor(props, context) {
super(props, context);
// Setup current state
this.currState = this.props.propStore.getState();
console.log('PropStore', this.currState.teamBowling);
// This component state
this.state = {
bowlerId: 0,
bowlerName: '',
markPrevOverFinished: false
};
// Setup variables
this.players = this.props.players;
// Bind this (so that we write short code in the onChange like onChange=this.func)
this.handleInputChange = this.handleInputChange.bind(this);
}
componentWillReceiveProps(nextProps, nextState){
//this.props.something // old value
//nextProps.something // new value
console.log('componentWillReceiveProps', nextProps.propStore.getState().teamBowling);
}
render() {
//console.log('BowlingBowler render()', this.props);
var responsiveWidth = {
width: '90vw',
transform: 'translate(-23%, 0%)'
};
console.log('BowlingAddBowler render()', this.currState.teamBowling.players);
return (
<div className="row">
<div className="col-xs-12">
<button className="btn" onClick={() => this.refs.dialogAddBowler.show()}>No Bowler Selected. Click To Select</button>
</div>
<SkyLight dialogStyles={responsiveWidth} hideOnOverlayClicked ref="dialogAddBowler" title="Select a new bowler">
<div>
<form onSubmit={this.handleSubmit.bind(this)}>
<label className="bg-yellow">
Total <span className="text-red">0</span> for the loss of <span className="text-red">0</span> wickets in <span className="text-red">0</span> overs
</label>
<div className="spacer-horizontal"></div>
<label>Who will bowl the next over ?</label>
<select name="bowlerId" value={this.state.bowlerId} onChange={this.handleInputChange} className="form-control">
<option value="">Select an existing bowler</option>
{
this.currState.teamBowling.players.map(function (player, index) {
return <option value="{player}" key={index}>{player}</option>
})
}
</select>
<div className="spacer-horizontal"></div>
<b>- OR -</b>
<input type="text" name="bowlerName" value={this.state.bowlerName} onChange={this.handleInputChange} className="form-control" />
<div className="spacer-horizontal"></div>
<input type="checkbox" name="markPrevOverFinished" checked={this.state.markPrevOverFinished} onChange={this.handleInputChange}/>
<label> Mark previous over finished</label>
<div className="spacer-horizontal"></div>
<div className="HorizLine"></div>
<div className="text-right">
<button type="submit" className="btn btn-primary"> Save </button>
</div>
</form>
</div>
</SkyLight>
</div>
)
}
}
This code:
this.currState = this.props.propStore.getState();
is in BowlingAddBowler's constructor and only runs first time when the class is instantiated. You can put it in componentWillReceiveProps of BowlingAddBowler too so that it runs when new data comes from server and parent component updates BowlingAddBowler.