I have a div which contains another div. The inner and outer div have bindings of two ViewModel. The inner ViewModel bindings do not work. My code looks like:
<div class='liveExample'>
<p>First name: <input data-bind='value: firstName' /></p>
<p>Last name: <input data-bind='value: lastName' /></p>
<h2>Hello, <span data-bind='text: fullName'> </span>!</h2>
<div class='liveExample2'>
<p>First name: <input data-bind='value: firstName2' /></p>
<p>Last name: <input data-bind='value: lastName2' /></p>
<h2>Hello, <span data-bind='text: fullName2'> </span>!</h2>
</div>
</div>
// Here's my data model1
var ViewModel = function(first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
};
// Here's my data model2
var ViewModel2 = function(first, last) {
this.firstName2 = ko.observable(first);
this.lastName2 = ko.observable(last);
this.fullName2 = ko.computed(function() {
return this.firstName2() + " " + this.lastName2();
}, this);
};
ko.applyBindings(new ViewModel("Planet", "Earth"),document.getElementById('liveExample'));
ko.applyBindings(new ViewModel2("Planet2", "Earth2"),document.getElementById('liveExample2'));
Your requirement can be accomplished by using a custom binding. Also you do not need two ViewModels here. It's just duplication of code.
jsFiddle here
<div id='liveExample'>
<p>First name: <input data-bind='value: firstName' /></p>
<p>Last name: <input data-bind='value: lastName' /></p>
<h2>Hello, <span data-bind='text: fullName'> </span>!</h2>
<div data-bind="stopBinding: true">
<div id='liveExample2'>
<p>First name: <input data-bind='value: firstName' /></p>
<p>Last name: <input data-bind='value: lastName' /></p>
<h2>Hello, <span data-bind='text: fullName'> </span>!</h2>
</div>
</div>
</div>
ko.bindingHandlers.stopBinding = {
init: function() {
return { controlsDescendantBindings: true };
}
};
// Here's my data model1
var ViewModel = function(first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
};
ko.applyBindings(new ViewModel("Planet","Earth"),document.getElementById('liveExample'));
ko.applyBindings(new ViewModel("Planet2","Earth2"),document.getElementById('liveExample2'));
Related
I have the following code but it does not post to my Subscriber collection. When I put in an email address it does not post to my subscriber collection type. Also it does not console.log
Using Nuxt3/Strapi4
<template>
<div class="relative flex justify-center w-full h-64 pb-16 mt-14 subscribe-bg">
<Container>
<div class="w-full mx-auto lg:w-3/6">
<div class="px-10 -mt-12 text-center bg-white rounded-lg shadow-xl py-9 subscribe-box">
<Heading tag="h3" font-style="h3">Subscribe</Heading>
<Heading tag="h2" font-style="h2">Never miss a planner</Heading>
<p
class="w-full px-2 mx-auto text-center pb-7 text-brand-grey-400"
>Subscribe to receice the worlds most cutting edge planner news direct to your inbox. Our newsletter is on fire.</p>
<div class="flex items-center">
<form #submit.prevent="handleSuscribe">
<input-field
id="email"
v-model="email.email"
type="email"
name="email"
placeholder="Your email"
class="w-3/4 mr-8"
/>
<Btn class="h-full" type="submit">Subscribe</Btn>
</form>
</div>
</div>
</div>
</Container>
</div>
</template>
<script setup>
import { useToast } from 'vue-toastification';
const toast = useToast();
const email = ref({ email: "" })
const handleSuscribe = async () => {
await $fetch("http://localhost:1337/api/subscribers", {
method: "POST",
body: {
data: {
email: email.value,
}
}
})
console.log(email.value)
console.log(handleSuscribe)
}
</script>
Tried to convert from the following code from Nuxt 2. It looked pretty simple at first but now I am running into issues.
<template>
<div
class="sm:flex mx-auto items-center m-10 justify-center space-x-6 sm:space-x-20 m-3 sm:m-6 mx-6"
>
<div>
<h1 class="text-lg m-7">Sign Up For NewsLetter</h1>
</div>
<div>
<form #submit="handleSuscribe">
<input
id=""
v-model="email"
class="p-2 m-3 sm:m-0 border border-solid border-t-0 border-l-0 border-r-0 border-b-1 outline-none border-black"
type="email"
name=""
placeholder="email"
/>
<button type="submit" class="button--grey">Subscribe</button>
</form>
</div>
</div>
</template>
<script>
export default {
name: 'NewsLetter',
data() {
return {
email: '',
}
},
methods: {
async handleSuscribe(e) {
e.preventDefault()
this.$swal({
title: 'Successful!',
text: 'Thanks for Subscribing',
icon: 'success',
button: 'Ok',
})
await this.$strapi.$subscribers.create({ Email: this.email })
this.email = '' // clear email input
},
},
}
</script>
We are developing a site using Angular 9.
We have also integrated a Unity3D WebGL build in it.
When I try to type something in a text/password/number input field inside one of my forms, it doesn't write anything and the field doesn't seem to receive the input; also, the variable I bound the field to is not updated with the new value.
What makes it weirder is that:
I can select the input field (it gets highlighted as if I can start typing)
I can do CTRL+C on the field and what I copied somewhere else is pasted, as expected
I can use the type="number" arrow selectors to set the value of the field
I cannot type from the keyboard in the fields
I can interact as expected with other form tags, such as <select>
If I reload the page, it usually starts working as expected and I can type into the fields
Here is the code from my login form (component.ts above, template HTML below)
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../auth.service'
import { first } from 'rxjs/operators';
import { Router, ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.less']
})
export class LoginComponent implements OnInit {
email: string = "";
password: string = "";
returnUrl: string = "home";
constructor(private router: Router, private route: ActivatedRoute, private authService: AuthService) { }
ngOnInit(): void {
let tmpReturnUrl = this.route.snapshot.queryParams["returnUrl"];
if (tmpReturnUrl != undefined)
{
console.log("true");
this.returnUrl = tmpReturnUrl;
}
else
console.log("false");
setInterval(() => {
console.log("EMAIL: " + this.email);
}, 1000);
}
onSubmit(){
this.authService.login(this.email, this.password)
.pipe(first())
.subscribe(
result => {
console.log("CAIOAOAOAOOA");
this.router.navigate([this.returnUrl]);
},
err => console.log(err)
);
}
}
<div class="card z-depth-5 w-50">
<div class="card-body">
<div class="card-title">Log in</div>
<div class="card-text">
<form #companyLoginForm="ngForm" (ngSubmit)="onSubmit()">
<mat-form-field>
<mat-label>Email: </mat-label>
<input matInput required type="text" name="email" id="email" [(ngModel)]="email">
</mat-form-field>
<mat-form-field>
<mat-label>Password: </mat-label>
<input matInput required type="password" name="password" id="password" [(ngModel)]="password">
</mat-form-field>
<button type="submit" [disabled]="!companyLoginForm.form.valid">Login</button>
</form>
<a routerLink="/company-register">
<button mdbBtn type="button" color="primary" class="relative waves-light">Sign Up</button>
</a>
</div>
</div>
</div>
And here, the code from another form where I also use type="number" and <select> (component.ts above, template HTML below)
import { Component, OnInit, Output } from '#angular/core';
import { BlockFormService } from '../block-form.service';
import { BlockData } from '../blockCardData';
import { BlockUtilsService } from '../block-utils.service';
import { ApiService } from '../../core/api.service'
import { NgForm } from '#angular/forms';
#Component({
selector: 'app-block-form',
templateUrl: './block-form.component.html',
styleUrls: ['./block-form.component.less']
})
export class BlockFormComponent implements OnInit {
updateComplete : Boolean = false;
materials : string[];
products : string[];
varieties : string[];
nations : string[];
// companies : {name: string, id: string}[] = [];
company : string = "";
colors : string[] = ["White", "Grey", "Black", "Brown", "Red", "Green", "Yellow", "Blue"];
blockData : BlockData = {_id : "", blockId: "", company: "", material: "", product: "",
variety: "", color: "", nation: "", modelName : "", imagePreview : "",
price: null, blockNumber: "",
length: null, height: null, width: null,
weight: null
};
imagePreview: File = null;
zipFile: File = null;
invalidUpload: boolean = false;
constructor( private blockFormService: BlockFormService, public blockUtils: BlockUtilsService, private companiesUtils: ApiService )
{ }
ngOnInit(): void {
this.materials = this.blockUtils.getMaterials();
this.colors = this.blockUtils.getColors();
this.companiesUtils.getLoggedCompany().subscribe(companiesResult => {
this.blockData.company = companiesResult._id;
this.company = companiesResult.name;
});
}
onImageSelected(event){
console.log(event.target.files[0]);
if (event.target.files[0].type === "image/png")
{
if (this.invalidUpload)
this.invalidUpload = false;
this.imagePreview = event.target.files[0];
}
else{
if (!this.invalidUpload)
this.invalidUpload = true;
event.target.value = null;
}
}
onMaterialSet(newMaterial): void{
console.log("Material set");
this.products = this.blockUtils.getProducts(newMaterial);
//console.log(this.products);
// if (this.products.length > 0)
// this.blockData.product = this.products[0];
// else
this.blockData.product = "";
this.onProductSet(this.blockData.product);
}
onProductSet(newProduct): void{
console.log("Product set");
this.varieties = this.blockUtils.getVarieties(this.blockData.material, newProduct);
// if (this.varieties.length > 0)
// this.blockData.variety = this.varieties[0];
// else
this.blockData.variety = "";
this.nations = this.blockUtils.getNations(this.blockData.material, this.blockData.product);
if (this.nations.length > 0)
this.blockData.nation = this.nations[0];
else
this.blockData.nation = "";
this.onVarietySet(this.blockData.variety);
}
onVarietySet(newVariety): void{
console.log("Variety set");
// this.nations = this.blockUtils.getNations(this.blockData.material, this.blockData.product);
// if (this.nations.length > 0)
// this.blockData.nation = this.nations[0];
// else
// this.blockData.nation = "";
}
onSubmit(blockForm : NgForm, imageField, zipField): void{
this.blockFormService.sendBlock(this.blockData, this.imagePreview, this.zipFile)
.subscribe(res => {
console.log("Sent!");
this.updateComplete = true;
});
this.blockData = {
_id: "", blockId: "", company: "", material: "", product: "",
variety: "", color: "", nation: "", modelName: "", imagePreview: "",
price: null, blockNumber: "",
length: null, height: null, width: null,
weight: null
};
blockForm.resetForm();
imageField.value = null;
zipField.value = null;
this.imagePreview = null;
this.zipFile = null;
}
}
<div class="form-group">
<div class="text-center" *ngIf='updateComplete'>
Block added successfuly
</div>
<form #blockForm="ngForm" (ngSubmit)="onSubmit(blockForm, imageField, zipField)">
<div class="container">
<div class="row">
<div class="col-3">
<mat-form-field>
<mat-label>Company: </mat-label>
<!-- <mat-select required [(ngModel)]="blockData.company" name="company-field"
id="company-field">
<mat-option selected [value]="company.id">{{company.name}}</mat-option>
</mat-select> -->
<input matInput disabled [value]="company" type="text" name="company-field" id="company-field">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Material: </mat-label>
<mat-select #matField required [(ngModel)]="blockData.material" name="kind-field"
id="kind-field" (selectionChange)="onMaterialSet(blockData.material)">
<mat-option *ngFor="let mat of materials" [value]="mat">{{mat}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Product: </mat-label>
<mat-select required [(ngModel)]="blockData.product" name="product-field"
id="product-field" (selectionChange)="onProductSet(blockData.product)">
<mat-option *ngFor="let prod of products" [value]="prod">{{prod}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Block Number: </mat-label>
<input matInput required [(ngModel)]="blockData.blockNumber" type="text" name="blockNumber-field" id="blockNumber-field">
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-3">
<mat-form-field>
<mat-label>Variety: </mat-label>
<mat-select required [(ngModel)]="blockData.variety" name="variety-field" id="variety-field"
placeholder="Variety" (selectionChange)="onVarietySet(blockData.variety)">
<mat-option *ngFor="let variety of varieties" [value]="variety">{{variety}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-3">
<!-- <label for="color-field">Color: </label> -->
<mat-form-field>
<mat-label>Color: </mat-label>
<mat-select required [(ngModel)]="blockData.color" name="color-field" id="color-field" placeholder="Color">
<mat-option *ngFor="let col of colors" [value]="col">{{col}}</mat-option>
</mat-select>
</mat-form-field>
<!-- <input #colField required [(ngModel)]="blockData.color" type="text" name="color-field" id="color-field" placeholder="Color"> -->
<!-- <color-circle #colorField [colors]='["#f44336", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#2196f3", "#03a9f4", "#00bcd4", "#009688", "#4caf50", "#8bc34a", "#cddc39", "#ffeb3b", "#ffc107", "#ff9800", "#ff5722", "#795548", "#607d8b"]' name="color-field" id="color-field" (onChange)="blockData.color = $event.color.hex"></color-circle> -->
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Nation: </mat-label>
<!-- <mat-select required [(ngModel)]="blockData.nation" name="nation-field"
id="nation-field">
<mat-option *ngFor="let nat of nations" [value]="nat">{{nat}}</mat-option>
</mat-select> -->
<input matInput disabled [(ngModel)]="blockData.nation" type="text" name="nation-field" id="nation-field">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Price: </mat-label>
<input matInput required [(ngModel)]="blockData.price" type="number" name="price-field" id="price-field">
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-3">
<mat-form-field>
<mat-label>Length: </mat-label>
<input matInput required [(ngModel)]="blockData.length" type="number" name="length-field" id="length-field">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Width: </mat-label>
<input matInput required [(ngModel)]="blockData.width" type="number" name="width-field" id="width-field">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Height: </mat-label>
<input matInput required [(ngModel)]="blockData.height" type="number" name="height-field" id="height-field">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Weight: </mat-label>
<input matInput required [(ngModel)]="blockData.weight" type="number" name="weight-field" id="weight-field">
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-3">
<div class="file-field">
<div class="btn btn-primary btn-sm float-left">
<label for="image-field">Upload preview image: </label>
<input #imageField (change)="onImageSelected($event)" name="image-field" id="image-field" type="file" accept=".png, image/png" placeholder="Upload your file">
</div>
</div>
</div>
<div class="col-3">
<div class="file-field">
<div class="btn btn-primary btn-sm float-left">
<label for="zip-field">Upload models' zip: </label>
<input #zipField (change)="zipFile = $event.target.files[0];" name="zip-field" id="zip-field" type="file" placeholder="Upload your file">
</div>
</div>
</div>
</div>
<button type="submit" [disabled]="!blockForm.form.valid || imagePreview == null || zipFile == null || blockData.company === ''">Submit</button>
</div>
</form>
</div>
I hope I was clear enough, any help is appreciated :)
Finally I found the source of the problem. In our website we have integrated a Unity3D WebGL build and, if I moved from the web page with Unity to the login page, the Unity process was still running. Unity had the focus of every input of the keyboard, so it was catching all the inputs.
We resolved it by quitting the Unity application when we change page. This way, input fields can receive inputs from the keyboard again.
Another solution, maybe (I have not tested it), could be to not make Unity get the inputs, as discussed in this Unity forum's thread or by setting WebGLInput.captureAllKeyboardInput to false.
I am submitting form via redux API call and getting response but on success response I am trying to reset form but that giving issue -
setState(...): Cannot update during an existing state transition (such as withinrenderor another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to 'componentWillMount'.
here is my from file -
=========================
import React from 'react';
import DefaultLayout from '../Layout/DefaultLayout';
//import $ from 'jquery';
import { connect } from 'react-redux';
import { contactRequest } from '../actions/signupActions';
import { bindActionCreators } from 'redux';
import validator from 'validator';
class Contactus extends React.Component {
constructor(props){
super(props);
document.title = "Contact Us";
this.errorMapping = {"100": "Your message has been submitted.",
"102": "Name cannot be empty.",
"104": "Email cannot be empty.",
"103": "Hotel cannot be empty.",
"105": "Incorrect email format.",
"106": "Phone cannot be empty."}
this.state = {name: '',email:'',message :''};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.baseState = this.state
}
handleInputChange(event) {
this.setState({ [event.target.name]: event.target.value});
}
handleSubmit(event) {
event.preventDefault();
this.props.contactRequest(this.state);
}
render(){
const style_1 = {height: '240px'};
const style_2 = {marginRight: '15px'};
const style_3 = {width: 'auto'};
return(
<DefaultLayout>
<section id="content">
<div className="content-wrap">
<div className="container clearfix">
<div className="col-md-6 bottommargin">
<section id="google-map" className="gmap" style={style_1} ></section>
</div>
<div className="col-md-6">
Click here to Send an Email
Send an Email
<div className="modal fade" id="contactFormModal" tabIndex="-1" role="dialog" aria-labelledby="contactFormModalLabel" aria-hidden="true">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-body">
<div className="contact-widget">
<div className="contact-form-result">
{this.props.resultMessage && this.props.resultMessage.status.map((msg, idx) => {
if(msg === 100) {
this.setState({name : "",email : ""});
return <span key={idx} id="succ_msg">{this.errorMapping[msg]}</span>
} else {
return <span key={idx} id="err_msg">{this.errorMapping[msg]}</span>
}
})
}
</div>
<form className="nobottommargin" id="r_contactform" name="r_contactform" method="post" onSubmit={this.handleSubmit} ref={(el) => this.myFormRef = el} >
<div className="form-process"></div>
<div className="col_half">
<label htmlFor="template-contactform-name">Name <small>*</small></label>
<input type="text" id="template-contactform-name" name="name" value={this.state.name} className="sm-form-control required" onChange={this.handleInputChange} />
</div>
<div className="col_half col_last">
<label htmlFor="template-contactform-email">Email <small>*</small></label>
<input type="email" id="template-contactform-email" name="email" value={this.state.email} className="required email sm-form-control" onChange={this.handleInputChange} />
</div>
<div className="clear"></div>
<div className="clear"></div>
<div className="col_half">
<label htmlFor="template-contactform-message">Message <small>*</small></label>
<textarea className="required sm-form-control" id="template-contactform-message" name="message" value={this.state.message} rows="6" cols="30" onChange={this.handleInputChange}></textarea>
<span className={this.state.messageError ? 'help-block error': '' }>{ this.state.messageError ? this.state.messageError: '' }</span>
</div>
<div className="col_full">
<button className="button button-3d nomargin" type="submit" id="contactform-submit" name="contactform-submit">Send Message</button>
</div>
</form>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</DefaultLayout>
);
}
}
function mapStateToProps(state){
console.log("View data :"+JSON.stringify(state.Contactdata));
return {
resultMessage: state.Contactdata
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({contactRequest: contactRequest}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps) (Contactus);
getting response in mapStateToProps function and trying to update state where I have applied condition if(msg === 100) .
Please let me know where I am doing wrong.
thanks
The right place to setState is not in the map function, since you are receiving props from redux, you can do it in the componentWillReceiveProps fucntion
class Contactus extends React.Component {
constructor(props){
super(props);
document.title = "Contact Us";
this.errorMapping = {"100": "Your message has been submitted.",
"102": "Name cannot be empty.",
"104": "Email cannot be empty.",
"103": "Hotel cannot be empty.",
"105": "Incorrect email format.",
"106": "Phone cannot be empty."}
this.state = {name: '',email:'',message :''};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.baseState = this.state
}
componentWillReceiveProps(nextProps) {
nextProps.resultMessage.status.forEach((msg, idx) => {
if(msg === 100) {
this.setState({name : "",email : ""});
}
}
}
handleInputChange(event) {
this.setState({ [event.target.name]: event.target.value});
}
handleSubmit(event) {
event.preventDefault();
this.props.contactRequest(this.state);
}
render(){
const style_1 = {height: '240px'};
const style_2 = {marginRight: '15px'};
const style_3 = {width: 'auto'};
return(
<DefaultLayout>
<section id="content">
<div className="content-wrap">
<div className="container clearfix">
<div className="col-md-6 bottommargin">
<section id="google-map" className="gmap" style={style_1} ></section>
</div>
<div className="col-md-6">
Click here to Send an Email
Send an Email
<div className="modal fade" id="contactFormModal" tabIndex="-1" role="dialog" aria-labelledby="contactFormModalLabel" aria-hidden="true">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-body">
<div className="contact-widget">
<div className="contact-form-result">
{this.props.resultMessage && this.props.resultMessage.status.map((msg, idx) => {
if(msg === 100) {
return <span key={idx} id="succ_msg">{this.errorMapping[msg]}</span>
} else {
return <span key={idx} id="err_msg">{this.errorMapping[msg]}</span>
}
})
}
</div>
<form className="nobottommargin" id="r_contactform" name="r_contactform" method="post" onSubmit={this.handleSubmit} ref={(el) => this.myFormRef = el} >
<div className="form-process"></div>
<div className="col_half">
<label htmlFor="template-contactform-name">Name <small>*</small></label>
<input type="text" id="template-contactform-name" name="name" value={this.state.name} className="sm-form-control required" onChange={this.handleInputChange} />
</div>
<div className="col_half col_last">
<label htmlFor="template-contactform-email">Email <small>*</small></label>
<input type="email" id="template-contactform-email" name="email" value={this.state.email} className="required email sm-form-control" onChange={this.handleInputChange} />
</div>
<div className="clear"></div>
<div className="clear"></div>
<div className="col_half">
<label htmlFor="template-contactform-message">Message <small>*</small></label>
<textarea className="required sm-form-control" id="template-contactform-message" name="message" value={this.state.message} rows="6" cols="30" onChange={this.handleInputChange}></textarea>
<span className={this.state.messageError ? 'help-block error': '' }>{ this.state.messageError ? this.state.messageError: '' }</span>
</div>
<div className="col_full">
<button className="button button-3d nomargin" type="submit" id="contactform-submit" name="contactform-submit">Send Message</button>
</div>
</form>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</DefaultLayout>
);
}
}
This is the reason, you are doing setState inside render method:
{this.props.resultMessage && this.props.resultMessage.status.map((msg, idx) => {
if(msg === 100) {
this.setState({name : "",email : ""});
.....
When msg==100 will be true, you are doing setState, again it will trigger re-rendering, again setState ....... infinite loop.
Remove that setState it will work.
Use componentWillReceiveProps lifecycle method, and do the setState inside that.
componentWillReceiveProps(newProps) {
newProps.resultMessage.status.forEach((msg, idx) => {
if(msg === 100) {
this.setState({
name : "",
email : ""
});
}
}
}
I want to make an app which displays some items, so I found the backand template (https://market.ionic.io/starters/backand-simple) and used it. I have about 40 items in my database, but the app only displays the first 20 items.
my controller.js
angular.module('SimpleRESTIonic.controllers', [])
.controller('LoginCtrl', function (Backand, $state, $rootScope, LoginService) {
var login = this;
function signin() {
LoginService.signin(login.email, login.password)
.then(function () {
onLogin();
}, function (error) {
console.log(error)
})
}
function onLogin(){
$rootScope.$broadcast('authorized');
login.email = '';
login.password = '';
$state.go('tab.dashboard');
}
function signout() {
LoginService.signout()
.then(function () {
//$state.go('tab.login');
login.email = '';
login.password = '';
$rootScope.$broadcast('logout');
$state.go($state.current, {}, {reload: true});
})
}
login.signin = signin;
login.signout = signout;
})
.controller('DashboardCtrl', function (ItemsModel, $rootScope) {
var vm = this;
function goToBackand() {
window.location = 'http://docs.backand.com';
}
function getAll() {
ItemsModel.all()
.then(function (result) {
vm.data = result.data.data;
});
}
function clearData(){
vm.data = null;
}
function create(object) {
ItemsModel.create(object)
.then(function (result) {
cancelCreate();
getAll();
});
}
function update(object) {
ItemsModel.update(object.id, object)
.then(function (result) {
cancelEditing();
getAll();
});
}
function deleteObject(id) {
ItemsModel.delete(id)
.then(function (result) {
cancelEditing();
getAll();
});
}
function initCreateForm() {
vm.newObject = {name: '', description: ''};
}
function setEdited(object) {
vm.edited = angular.copy(object);
vm.isEditing = true;
}
function isCurrent(id) {
return vm.edited !== null && vm.edited.id === id;
}
function cancelEditing() {
vm.edited = null;
vm.isEditing = false;
}
function cancelCreate() {
initCreateForm();
vm.isCreating = false;
}
vm.objects = [];
vm.edited = null;
vm.isEditing = false;
vm.isCreating = false;
vm.getAll = getAll;
vm.create = create;
vm.update = update;
vm.delete = deleteObject;
vm.setEdited = setEdited;
vm.isCurrent = isCurrent;
vm.cancelEditing = cancelEditing;
vm.cancelCreate = cancelCreate;
vm.goToBackand = goToBackand;
vm.isAuthorized = false;
$rootScope.$on('authorized', function () {
vm.isAuthorized = true;
getAll();
});
$rootScope.$on('logout', function () {
clearData();
});
if(!vm.isAuthorized){
$rootScope.$broadcast('logout');
}
initCreateForm();
getAll();
});
my services.js
angular.module('SimpleRESTIonic.services', [])
.service('APIInterceptor', function ($rootScope, $q) {
var service = this;
service.responseError = function (response) {
if (response.status === 401) {
$rootScope.$broadcast('unauthorized');
}
return $q.reject(response);
};
})
.service('ItemsModel', function ($http, Backand) {
var service = this,
baseUrl = '/1/objects/',
objectName = 'items/';
function getUrl() {
return Backand.getApiUrl() + baseUrl + objectName;
}
function getUrlForId(id) {
return getUrl() + id;
}
service.all = function () {
return $http.get(getUrl());
};
service.fetch = function (id) {
return $http.get(getUrlForId(id));
};
service.create = function (object) {
return $http.post(getUrl(), object);
};
service.update = function (id, object) {
return $http.put(getUrlForId(id), object);
};
service.delete = function (id) {
return $http.delete(getUrlForId(id));
};
})
.service('LoginService', function (Backand) {
var service = this;
service.signin = function (email, password, appName) {
//call Backand for sign in
return Backand.signin(email, password);
};
service.anonymousLogin= function(){
// don't have to do anything here,
// because we set app token att app.js
}
service.signout = function () {
return Backand.signout();
};
});
my dashboard-tab //which displays the items
<ion-view view-title="Produkte">
<div ng-if="!vm.isCreating && !vm.isEditing">
<ion-content class="padding has-header">
<!-- LIST -->
<div class="bar bar-header bar-balanced">
<span ng-click="vm.isCreating = true"><i class='icon ion-plus-round new-item'> Erstellen</i></span>
</div>
<div class="bar bar-subheader">
<div class="list card" ng-repeat="object in vm.data"
ng-class="{'active':vm.isCurrent(object.id)}">
<div class="item item-icon-right item-icon-left">
<i class="ion-compose icon" ng-click="vm.setEdited(object)"></i>
<h2 class="text-center"><b>{{object.name}}</b></h2>
<i class="icon ion-close-round" ng-click="vm.delete(object.id)"></i>
</div>
<div class="text-center">
{{object.description}}
</div>
<div class="item item-body">
<p style="text-align:center;"><img src="{{object.imgurl}}" style="max-width: 250px; max-height: 250px" /></p>
</div>
<div class="text-center">
{{object.price}} Euro
</div>
</div>
</div>
</ion-content>
</div>
<div ng-if="vm.isCreating">
<ion-content class="padding has-header">
<!-- Erstellen -->
<div class="bar bar-header">
<h2 class="title">Erstelle ein Produkt</h2>
<span ng-click="vm.cancelCreate()" class="cancel-create">Abbruch</span>
</div>
<div class="bar bar-subheader">
<form class="create-form" role="form"
ng-submit="vm.create(vm.newObject)" novalidate>
<div class="list">
<label class="item item-input item-stacked-label">
<span class="input-label">Name</span>
<input type="text" class="form-control"
ng-model="vm.newObject.name"
placeholder="Gib einen Namen ein">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Beschreibung</span>
<textarea placeholder="Beschreibung" class="form-control"
ng-model="vm.newObject.description"></textarea>
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Preis</span>
<textarea placeholder="Preis" class="form-control"
ng-model="vm.newObject.price"
typeof="float"></textarea>
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Bild</span>
<input type="text" class="form-control"
ng-model="vm.newObject.imgurl"
placeholder="Gib einen Bildlink ein">
</label>
</div>
<button class="button button-block button-balanced" type="submit">Fertig</button>
</form>
</div>
</ion-content>
</div>
<div ng-if="vm.isEditing && !vm.isCreating">
<ion-content class="padding has-header">
<!-- Bearbeiten -->
<div class="bar bar-header bar-secondary">
<h1 class="title">Bearbeiten</h1>
<span ng-click="vm.cancelEditing()" class="cancel-create">Abbrechen</span>
</div>
<div class="bar bar-subheader">
<form class="edit-form" role="form"
ng-submit="vm.update(vm.edited)" novalidate>
<div class="list">
<label class="item item-input item-stacked-label">
<span class="input-label">Name</span>
<input type="text" class="form-control"
ng-model="vm.edited.name"
placeholder="Gib einen Namen ein">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Beschreibung</span>
<textarea class="form-control"
ng-model="vm.edited.description"
placeholder="Beschreibung"></textarea>
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Preis</span>
<textarea placeholder="Preis" class="form-control"
ng-model="vm.edited.price"
type="float"></textarea>
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Bild</span>
<textarea class="form-control"
ng-model="vm.edited.imgurl"
placeholder="Bildlink"></textarea>
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Auswählen</span>
<textarea class="form-control"
ng-model="vm.edited.check"
placeholder="true" type="boolean"></textarea>
</label>
</div>
<button class="button button-block button-balanced" type="submit">Speichern</button>
</form>
</div>
</ion-content>
</div>
thanks for using Backand! There is a default page size filter that you can modify in your getList() call. It is available in our new SDK - if you update to the latest version of the starter project you downloaded, it should already have the appropriate changes built-in. For reference, our new SDK can be found at https://github.com/backand/vanilla-sdk
Regarding resolving your issue, in order to adjust the page size, you can pass in an additional parameter to the getList function that dynamically changes the number of records you can retrieve. Here's some sample code that matches your use case:
service.all = function () {
params = { pageSize: 100 }; // Changes page size to 100
return Backand.object.getList('items', params);
};
Using the old SDK, you can do something similar by appending the parameters query param to the URL you use to drive your GET request.
I'm newbie in Angular 2 and trying to write a simple ng-form following by official tutorial.
If I'm using simple array from tutorial, it works fine:
powers = ['Really Smart', 'Super Flexible',
'Super Hot', 'Weather Changer'];
But when I'm changing it on my custom array from http
public departments = [];
constructor(http: Http) {
http.get('/api/departments')
.map((res: Response) => res.json())
.subscribe((departments: Array<Object>) => this.departments = departments);
}
I'm getting an error:
error_handler.js:51 Error: Uncaught (in promise): Error: Error in ./AddClientComponent class AddClientComponent - inline template:41:12 caused by: Cannot find a differ supporting object '[object Object]' of type 'departments'. NgFor only supports binding to Iterables such as Arrays.
So where is my mistake and what am I missing? thanks in advance.
AddClientComponent
import 'rxjs/add/operator/map';
import {Component} from '#angular/core';
import {Http, Response} from '#angular/http';
import { DepartmentsComponent } from '../departments/departments.component';
#Component({
selector: 'app-add-client',
templateUrl: './add-client.component.html',
styleUrls: ['./add-client.component.css']
})
export class AddClientComponent {
public departments = [];
public firstName = '';
public lastName = '';
public id = null;
constructor(http: Http) {
http.get('/api/departments')
.map((res: Response) => res.json())
.subscribe((departments: Array<Object>) => this.departments = departments);
}
model = new Employee(
this.id,
this.firstName,
this.lastName,
this.departments
);
submitted = false;
onSubmit() { this.submitted = true; }
active = true;
}
export class Employee {
constructor(
public id: number,
public firstName: string,
public lastName: string,
public departments: any
) { }
}
html
<div class="container">
<div [hidden]="submitted">
<h1>Employee Form</h1>
<form *ngIf="active" (ngSubmit)="onSubmit()" #employeeForm="ngForm">
<div class="form-group">
<label for="firstName">First Name</label>
<input type="text" class="form-control" id="firstName"
required
[(ngModel)]="model.firstName"
name="firstName"
#firstName="ngModel" >
<div [hidden]="firstName.valid || firstName.pristine"
class="alert alert-danger">
First Name is required
</div>
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input type="text" class="form-control" id="lastName"
required
[(ngModel)]="model.lastName"
name="lastName"
#lastName="ngModel" >
<div [hidden]="lastName.valid || lastName.pristine"
class="alert alert-danger">
Last Name is required
</div>
</div>
<div class="form-group">
<label for="departments">Department</label>
<select class="form-control" id="departments"
required
[(ngModel)]="model.departments"
name="departments"
#departments="ngModel" >
<option
*ngFor="let department of departments"
[value]="department">{{department.name}}
</option>
</select>
<div [hidden]="departments.valid || departments.pristine"
class="alert alert-danger">
Department is required
</div>
</div>
<button type="submit"
class="btn btn-default"
[disabled]="!employeeForm.form.valid">Submit
</button>
<!--<button type="button"-->
<!--class="btn btn-default"-->
<!--(click)="newHero()">New Hero-->
<!--</button>-->
</form>
</div>
<div [hidden]="!submitted">
<h2>You submitted the following:</h2>
<div class="row">
<div class="col-xs-3">First Name</div>
<div class="col-xs-9 pull-left">{{ model.firstName }}</div>
</div>
<div class="row">
<div class="col-xs-3">Last Name</div>
<div class="col-xs-9 pull-left">{{ model.lastName }}</div>
</div>
<div class="row">
<div class="col-xs-3">Department</div>
<div class="col-xs-9 pull-left">{{ model.departments }}</div>
</div>
<br>
<button class="btn btn-default" (click)="submitted=false">Edit</button>
</div>
</div>
Use a different name for
#departments="ngModel"
I think it overloads the departments property of the class used in *ngFor
Try changing type
public departments: Array<any> = [];
constructor(http: Http) {
http.get('/api/departments')
.map((res: Response) => res.json())
.subscribe((departments: Array<any>) => this.departments = departments);
}