how to delete multiple items with checkbox in ionic 3 - checkbox

I would like to know how to delete multiple items from the list in Ionic 3, using CheckBox, here is my code, in the delete () function I do not know how to only exclude the products that are checked with the checkbox. I thought that this would work but did not delete anything . If anyone can help me, thank you.
produto.html
<ion-item-sliding *ngFor="let produto of produtos">
<ion-item>
<input [(ngModel)]="modelo[produto.id]" value="{{produto.id}}" name="modelo" type="checkbox" ng-checked="produto.checked">{{produto.id}}
<h1> {{ produto.barra }}</h1>
<h3> {{ produto.deposito_nome }}</h3>
<h3> {{ produto.quantidade }}</h3>
<!--<h2 class="price">{{ produto.preco | currency:'BRL':true }}</h2> -->
</ion-item>
</ion-item-sliding>
</ion-list>
<button ion-button (click)="excluir()">Excluir Todos</button>
import { Component } from '#angular/core';
import { DatabaseProvider } from '../../providers/database/database';
import { SQLiteObject } from '#ionic-native/sqlite';
import { NavController, NavParams, ToastController } from 'ionic-angular';
import { InventarioProvider, Product } from '../../providers/inventario/inventario';
import { RestProvider } from '../../providers/rest/rest';
import { HomePage } from '../home/home';
#Component({
selector: 'page-inventario',
templateUrl: 'inventario.html',
})
export class InventarioPage {
produtos: any[] = [];
modelo: any[] = [];
this.model = new Product();
if (this.navParams.data.id) {
this.inventarioProvider.get(this.navParams.data.id)
.then((result: any) => {
this.model = result;
})
}
}
ionViewDidEnter() {
this.getAllProdutos();
}
getAllProdutos() {
this.inventarioProvider.getAll()
.then((result: any[]) => {
this.produtos = result;
});
}
excluir() {
this.produtos.forEach(function (produto) {
if (produto.checked) {
this.modelo[produto.id] = produto.checked;
return this.dbProvider.getDB()
.then((db: SQLiteObject) => {
let sql = 'delete from inventario where id = ?';
let data = [produto.id];
return db.executeSql(sql, data)
})
}
})
}
}

Hey I never worked with SQlite but assuming the other parts of your code work including the db handling, you need to do something like the below in your delete method:
excluir() {
// create comma separated list of products to be deleted from db:
const toBeDeleted = this.produtos.filter(produto => produto.checked === true);
// now execute db script to delete multiple products:
return this.dbProvider.getDB().then((db: SQLiteObject) => {
// here i might be wrong but you should be able to delete all items with ids in one operation, don't use loop as it may get expensive:
db.delete("inventario", "id IN (?)", toBeDeleted.join())
db.close()
}).then(() => {
// now do the modelo step (not sure what is this though in your case):
toBeDeleted.forEach(produto => {
this.modelo[produto.id] = produto.checked;
})
// finally update product array by filtering out deleted items:
this.produtos = this.produtos.filter(produto => produto.checked === false);
})
}
Please note I am not entirely sure how you use delete multiple items using SQlite, but I hope you know that part. I think you might need to do this way:
db.delete("inventario", "id IN (" + toBeDeleted.join() + ")", null)

Related

How do I get the decimal in the right place with mongoose-currency?

I have implemented mongoose-currency in my User model:
const mongoose = require("mongoose");
const { Schema } = mongoose;
require("mongoose-currency").loadType(mongoose);
const Currency = mongoose.Types.Currency;
const userSchema = new Schema({
googleId: String,
paid: { type: Currency },
});
mongoose.model("users", userSchema);
but even if I add toFixed(2) on the client side:
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
class Header extends Component {
renderContent() {
switch (this.props.auth) {
case null:
return;
case false:
return (
<li>
<a href='/auth/google'>Login With Google</a>
</li>
);
default:
return [
<li key='1'>Paid: ${this.props.auth.paid.toFixed(2)}</li>,
<li key='2'>
<a href='/api/logout'>Logout</a>
</li>,
];
}
}
I get $1000.00 instead of $10.00, how do I get the decimal point to work without adding two more zeroes?
So I tried this approach:
const mongoose = require("mongoose");
const { Schema } = mongoose;
const userSchema = new Schema({
googleId: String,
paid: { type: Number, get: getPaid },
});
const getPaid = userSchema.path("paid").get(function (p) {
return (p / 100).toFixed(2);
});
mongoose.model("users", userSchema);
but I get the ReferenceError: Cannot access 'getPaid' before initialization
You should define a getter for your schema like so:
userSchema.path('paid').get(function(p) {
return (p / 100).toFixed(2);
});
ADDED:
There is no need to reference your getter like this:
paid: { type: Number, get: getPaid },
Getters work when you try to access the the path. So this is how you should do it:
const userSchema = new Schema({
googleId: String,
paid: { type: Number },
});
userSchema.path("paid").get(function (p) {
return (p / 100).toFixed(2);
});
However, there is a gotcha there: in order for the getter to trigger, you need to explicitly access the path. As such, when you search you collection, you will need to call up the path from the doc that gets returned:
userSchema.findById('5fc9c809fc360d373b3d77b8')
.then(u => {
console.log(u) // <- this will show the original "paid" path
console.log(u.paid) // <- This will give you the formatted "paid" path
})
Just FYI, to do it the way you attempted, you would need to write your code like so (which would accomplish the same thing as describe above):
const userSchema = new Schema({
googleId: String,
paid: { type: Number, get: getPaid },
});
function getPaid(p) {
return (p / 100).toFixed(2);
});
While the solution offered should logically work, it just did not work for me because I would get issues with reference errors regarding initialization and when I would solve that, it would still render ten dollars as $ 1000.00, so I finally came up with a solution that works for me:
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
class Header extends Component {
parsedNumber() {
return (this.props.auth.paid / 100).toFixed(2);
}
renderContent() {
switch (this.props.auth) {
case null:
return;
case false:
return (
<li>
<a href='/auth/google'>Login With Google</a>
</li>
);
default:
return [
<li key='1'>Paid: ${this.parsedNumber()}</li>,
<li key='2'>
<a href='/api/logout'>Logout</a>
</li>,
];
}
}
After so much trial and error and colleagues such as codemonkey helping me out, I realized I had no choice but to somehow work on getting those decimal places to show up at the point that the paid property is rendering and so I came up with the above and it works. Now I get $10.00 as opposed to $1000.00.

Google Apps Script & React.js : DELETE https://mygoogleappapi.com/exec 405 (Method Not Allowed)

Thank you for reading!
I am learning how to use GAS now,
I can't delete the specific row I selected on google spread sheet.
I got the theme error after trying to delete using "axios.delete method" when I used react app and google script api.
I already passed GET method and POST method using axios. Actually , I could get and post my data from my google spread sheet.
but deleting could not access well.
I found this error 405 is not allowed to access my google sheet, but Why can I get this error even though the post method was accessible?
My App script or My react.js code need to have any code else ? I can't solve this problem...
I want to solve this error and delete the specific row I selected. Also, I want to know a workaround for this error.
Do you have any idea ? If you have some good idea,Could you tell me please ?
Thank you for reading.
this is my App script code.
function doDelete(req, sheet) {
var id = req.parameter.id;
var Row = sheet.getLastRow();
for (var i = 1; i <= Row; i++) {
var idTemp = sheet.getRange(i, 1).getValue();
if (idTemp == id) {
sheet.deleteRow(i);
}
}
}
this is my reactjs code.
import React,{ useState , Component } from 'react';
import Paper from '#material-ui/core/Paper';
import Grid from '#material-ui/core/Grid';
import axios from 'axios';
axios.defaults.baseURL = 'http://localhost:3000';
var optionAxios = {
headers: {
'Content-Type': 'application/json;charset=utf-8',
'Access-Control-Allow-Origin':'*' ,
}
}
const api = 'https://mygoogleappscriptapi.com/exec';
class Price extends Component {
constructor(){
super();
this.state = {
info: []
};
this.getInfo();
this.createInfo = this.createInfo.bind(this);
this.deleteInfo = this.deleteInfo.bind(this);
};
// accessed get!
getInfo = () =>{
axios.get(api)
.then((res) =>{
console.log(res.data)
this.setState({
info: res.data
})
})
}
// accessed post!
createInfo = () =>{
axios.post(api,{
product: "hoge",
price: 1000,
miniLot: 1000,
cartonSize: "40*30*50"
},optionAxios)
.then((res) => {
this.getInfo(res);
})
}
// cant't access delete!
deleteInfo = (e) => {
console.log(e);
axios.delete(api,{
id: e,
},optionAxios)
.then((res) =>{
this.getInfo(res);
console.log('success!');
})
}
render(){
return (
<div className={this.root}>
<Grid container>
<Grid item xs={11}>
<button onClick={this.createInfo}>createButon</button>
<Paper>
{this.state.info.map(info => <div key={info.id}>
{info.product}
<button onClick={() => this.deleteInfo(info.id)}>×</button>
</div>)}
</Paper>
</Grid>
</Grid>
</div>
);
}
}
export default Price;
Only the following HTTP methods are supported:
POST
GET
DELETE method is not supported by google-apps-script-web-application.
You can use post:
Server side:
function doPost(e){
if(e.parameter.option === "DELETE") return doDelete(e);
/*rest of doPost here*/
}
React:
// convert to axios.post
deleteInfo = (e) => {
console.log(e);
axios.post(api,{//modified
id: e,
option: "DELETE",//added
},optionAxios)
.then((res) =>{
this.getInfo(res);
console.log('success!');
})
}
Try this:
function doDelete(req, sh) {
var id = req.parameter.id;
const ss=SpreadsheetApp.getActive();
sh=sh||ss.getActiveSheet();
var vs=sh.getRange(1,1,sh.getLastRow(),1).getValues();
var d=0;
for (var i=0;i<vs.length;i++) {
if (vs[i][0]== id) {
sh.deleteRow(i+1-d++);
}
}
}

Observable to Array *ngFor saying undefined

I am new to Angular. I have a Node and Express backend pulling data from an MS SQL database. If I go to the endpoint URL it displays my data as JSON. I am running on localhost so I set a proxy for CORS. I have a class that defines the data, a service that pulls the data from the endpoint and a component that tries to set an array equal to the data pulled from the service. The HTML has an *ngFor that is supposed to loop through the values and display them in a grid.
If I call my data in my component through my service, so this.userService.getUsers(), and do a console.log I can see the recordset in the browser console. I try to set the array equal to the userService.getUsers() and then call the array and I get "undefined". Being that I am new, I have tried to follow the Heroes tutorial and that did not work. I spent a day searching Google and trying different solutions that I have come across but they all come up as undefined. I will attach the code here. If someone can guide me a bit, it would be much appreciated.
User class defining User:
export class User{
id: number;
ccn: string;
firstName: string;
lastName: string;
email: string;
}
User Service doing Http request:
import { Injectable } from '#angular/core';
import { User } from './user';
import { USERS } from './mock-users';
import { MessageService } from './message.service';
import { Observable, of } from 'rxjs';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class UserService {
private userURL = 'api/users'
//private userURL = 'localhost:5000'
httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
constructor(
private http: HttpClient,
private messageService: MessageService) { }
//getUsers(): Observable<User[]> {
// this.messageService.add('UserService: fetched users');
// return of(USERS);
//}
/** GET users from the server */
getUsers(): Observable<User[]> {
//console.log('getting users');
return this.http.get<User[]>("http://localhost:5000/api/user")
.pipe(
tap(_ => this.log('Fetched users')),
catchError(this.handleError<User[]>('getUsers', []))
);
//return this.http.get<User[]>("http://localhost:5000/api/user");
//console.log('got users');
}
/* GET heroes whose name contains search term */
searchUsers(term: string): Observable<User[]> {
if (!term.trim()) {
// if not search term, return empty hero array.
return of([]);
}
return this.http.get<User[]>(`${this.userURL}/?ccn=${term}`).pipe(
tap(_ => this.log(`found users matching "${term}"`)),
catchError(this.handleError<User[]>('searchUsers', []))
);
}
addUser (user: User): Observable<User> {
return this.http.post<User>(this.userURL, user, this.httpOptions).pipe(
tap((newUser: User) => this.log(`added user w/ id=${newUser.id}`)),
catchError(this.handleError<User>('addUser'))
);
}
private handleError<T> (operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
console.error(error);
this.log(`${operation} failed: ${error.message}`);
return of(result as T);
};
}
private log(message: string) {
this.messageService.add(`User service: ${message}`);
}
}
Display Users Component TS file:
import { Component, OnInit } from '#angular/core';
//import { USERS } from '../mock-users';
import { UserService } from '../user.service';
import { User } from '../user';
import { Observable, of } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import { element } from 'protractor';
#Component({
selector: 'app-display-users',
templateUrl: './display-users.component.html',
styleUrls: ['./display-users.component.css']
})
export class DisplayUsersComponent implements OnInit {
users: User[] = [];
constructor(private userService: UserService) { }
//users$ = this.getUsers();
ngOnInit() {
this.getUsers();
console.log(this.userService.getUsers());
this.userService.getUsers().forEach(element => {
console.log(element);
});
}
getUsers(): void {
/*this.userService.getUsers()
.subscribe(users => this.users = users);*/
const userObservable = this.userService.getUsers();
userObservable.subscribe((userData: User[]) => {
this.users = userData;
});
}
}
Display Users Component HTML:
<div class="clr-row">
<div class="clr-col-lg-11 clr-col-md-11 clr-col-11 main-div">
<div class="card card-style" style="box-shadow: 0 0 0 0;">
<div class="card-header">
<h1><img src="../assets/images/BSOLOGO_gray.png" class="title-img"><span class="title"> Users</span></h1>
</div>
<div class="card-block">
<div class="card-title">
<clr-datagrid>
<clr-dg-column>CCN</clr-dg-column>
<clr-dg-column>Last Name</clr-dg-column>
<clr-dg-column>First Name</clr-dg-column>
<clr-dg-column>Email</clr-dg-column>
<clr-dg-row *ngFor="let user of users">
<clr-dg-cell>{{user.ccn}}</clr-dg-cell>
<clr-dg-cell>{{user.lastName}}</clr-dg-cell>
<clr-dg-cell>{{user.firstName}}</clr-dg-cell>
<clr-dg-cell>{{user.email}}</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>{{users.length}} users</clr-dg-footer>
</clr-datagrid>
</div>
</div>
</div>
</div>
</div>
Any help would be greatly appreciated!
UPDATED
Ypu can replace getUsers on both classes by these. HTML looks fine to me. I converted users to public too.
//userService
getUsers(callback: Function) {
return this.http.get<User[]>("http://localhost:5000/api/user")
.subscribe(
response => callback(response)
);
}
//Component
public users: User[] = [];
getUsers(): void {
this.userService.getUsers((result) => {this.users = result;})
}
If you do not need it to be Observable you can use toPromise() and using async/await makes it waaay easier
Service
async getUsers(): Promise<User[]> {
return await this.http.get<User[]>('http://localhost:5000/api/user').toPromise();
}
Component.ts
users: User[] = [];
async ngOnInit() {
this.users = await this.userService.getUsers();
}
Component.html
<clr-datagrid *ngIf="users">
<clr-dg-column>CCN</clr-dg-column>
<clr-dg-column>Last Name</clr-dg-column>
<clr-dg-column>First Name</clr-dg-column>
<clr-dg-column>Email</clr-dg-column>
<clr-dg-row *ngFor="let user of users">
<clr-dg-cell>{{user.ccn}}</clr-dg-cell>
<clr-dg-cell>{{user.lastName}}</clr-dg-cell>
<clr-dg-cell>{{user.firstName}}</clr-dg-cell>
<clr-dg-cell>{{user.email}}</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>{{users.length}} users</clr-dg-footer>
</clr-datagrid>
My issue has been resolved. In my SQL statement I was calling SELECT * FROM table FOR JSON PATH which was creating a weird object being pulled from the server. Removing the FOR JSON PATH provided JSON data. Then the second part of my issue was mapping my DB fields with my user class.
This was done like this:
request.query('SELECT * FROM Table ORDER BY myField', function (err, recordset) {
if (err) console.log(err);
const records = recordset.recordset;
const result = records.map(r => { return { id: r.tableID, field1: r.dbField1, field2: r.dbField2, field3: r.dbField3, field4: r.dbField4}});
res.send(result);
});
I hope this helps someone! Thanks to everyone that posted to help me.

Trying to get a length on a key value on an object which is inside an object within an array of objects

I am trying to create a score count for two teams. The score is an array which differentiates by defining if the goal was scored by a home or away team (which is a separate object within the score array). I need to get the count for the number of times a goal has been scored which carries an id of either 1 or 2.
I've tried using query selectors within the DOM, but with the request times, the score doesn't often render properly - the list length doesn't seem to get counted and stays at 0.
I have also tried to filter the count length whilst making a request post-subscription to the service within the component. But this again didn't work. The below code is an example.
This states that goalCount.filter is not a function.
getScore(): void {
this.ScoreService.getScore()
.subscribe(score => {
this.score = score;
const goalCount = this.score;
this.count = goalCount.filter((obj) => obj.side.data.id === '1').length;
});
}
then {{ count }} is bound to the view, but the above error displays.
console log of score - editor is so bad and formatting it takes ages:
I expect that when the server sends back a new goalscorer, the ngif decides which column to put it in and the length of that list in the DOM is then printed above it.
e.g
1
Smith, '89
2
Perez, '30
Taylor,'45
awayscore.component.ts
import { Component, OnInit, AfterViewInit, Input, OnDestroy } from '#angular/core';
import { Subscription } from 'rxjs/Subscription';
import { UpdateService } from '../update.service';
import { Stats } from '../stats';
import { StatsService } from '../stats.service';
import { Score } from '../score';
import { ScoreService } from '../score.service';
import { ConfigService } from '../../../shared/config/config.service';
import { Config } from '../../../shared/config/config';
import { environment } from '../../../environments/environment';
#Component({
selector: 'app-away-score',
templateUrl: './away-score.component.html'
})
export class AwayScoreComponent implements OnInit, AfterViewInit, OnDestroy {
#Input()
away: Stats;
private subscription: Subscription;
config: Config[];
stats: Stats[];
score: Score[];
imageUrl: string;
count: number;
constructor(
private StatsService: StatsService,
private ScoreService: ScoreService,
private configService: ConfigService,
private updateService: UpdateService) {
}
ngOnInit() {
this.getConfig();
this.getStat();
this.getScore();
this.imageUrl = environment.image_url;
this.subscription = this.updateService.updateObservables.subscribe((res) => {
if (res.hasOwnProperty('option') && res.option === 'call_score_component') {
console.log(res.value);
}
})
}
ngAfterViewInit() {
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
getConfig(): void {
this.configService.getConfig()
.subscribe(config => this.config = config);
}
getStat(): void {
this.StatsService.getStats()
.subscribe(stats => this.stats = stats);
}
getScore(): void {
this.ScoreService.getScore()
.subscribe(score => {
this.score = score;
});
}
}
awayscore.component.html:
<span *ngIf="away">
<ng-container *ngIf="config">
<img *ngIf="away.away_badge.data" class="avatar" [src]="imageUrl + away.away_badge.data.url">
<h4
*ngFor="let c of config;"
[style.font-family]="c.header_font.data.font_family"
[style.text-transform]="c.header_text_case.data.text_case"
[style.color]="'#' + c.secondary_color.data.hex_code">
{{ away.away_team }}</h4>
</ng-container>
<h1>{{ count }}</h1>
<ul #awayScore *ngIf="score">
<ng-container *ngFor="let s of score.data">
<li *ngIf="s.side.data.side === 'Away'">
<small>{{ s.goal_scorer }} '{{ s.time_of_goal }}</small>
</li>
</ng-container>
</ul>
</span>
score service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { _throw } from 'rxjs/observable/throw';
import { catchError, retry } from 'rxjs/operators';
import { environment } from '../../environments/environment';
#Injectable()
export class ScoreService {
url = environment.api_url;
private scoreURL = this.url + 'score/rows';
data: any = {};
constructor(private http: HttpClient) { }
getScore() {
return this.http.get(this.scoreURL)
.pipe(
retry(1),
catchError(this.handleError),
);
}
handleError(error) {
let errorMessage = '';
if (error.error) {
errorMessage = error.error.message;
} else {
errorMessage = error;
}
return _throw(errorMessage);
}
}
You are trying to access an array but its not. Your score contains a property data which is an array. Try this out:
getScore(): void {
this.ScoreService.getScore()
.subscribe(score => {
this.score = score.data;
const goalCount = this.score;
this.count = goalCount.filter((obj) => obj.side.data.id === '1').length;
});

Passing data from service to angular components

I am reading data from a firebase database and creating some objects based on the data received and pushing the data into a list. But the control goes back to the component before the objects are created or pushed into the list. I am confused to use any life cycle hooks in this approach.
Class Service(){
questions: QuestionsData<any>[]=[];
getQuestions(FormKey: string) {
var dbQuestions = this.af.list('/elements', {
query: {
limitToLast: 200,
orderByChild: 'formid',
equalTo: FormKey
}
})
dbQuestions.subscribe(snapshots=>{
snapshots.forEach(elementData => {
this.questions.push(new TextboxQuestion({
key: elementData.elementname,
label: elementData.displaytext,
value: elementData.elementvalue,
required: false,
order: elementData.sortorder
}))
}
}
}
Can anyone suggest how to consume this data in my component.
As JB Nizet mentioned in the comments, you should not subscribe to the observable and unwrap it in your template as you are currently doing. Angular provides the async pipe to handle that subscription for you. You simply want to map your data to TextBoxQuestion's. You can do that with the following code.
class MyComponent {
questions$: QuestionsData<any>[]=[];
getQuestions(FormKey: string) {
const dbQuestions$ = this.af.list('/elements', {
query: {
limitToLast: 200,
orderByChild: 'formid',
equalTo: FormKey
}
});
this.questions$ = dbQuestions$.map(snapshots =>
snapshots.map(data => new TextBoxQuestion({
key: data.elementname,
// and so on...
});
}
}
If you want to run that when your component initializes, use the OnInit lifecycle hook:
ngOnInit() {
this.getQuestions(/* form key */);
}
And then use the async pipe in your template like this:
<ul>
<li *ngFor="let question of questions$ | async">
{{ question.key }}
</li>
</ul>
Your service should be more or less like this:
import 'rxjs/add/operator/map'
Class Service() {
getQuestions(FormKey: string): Observable<QuestionsData<any>[]> {
return dbQuestions = this.af.list('/elements', {
query: {
limitToLast: 200,
orderByChild: 'formid',
equalTo: FormKey
}
}).map(snapshots=>{
conts questions: QuestionsData<any>[]=[];
snapshots.forEach(elementData => {
questions.push(new TextboxQuestion({
key: elementData.elementname,
label: elementData.displaytext,
value: elementData.elementvalue,
required: false,
order: elementData.sortorder
}))
})
return questions;
})
}
}
And in the component:
serviceInstance.getQuestions(FormKey).subscribe(questions => {
// your code here
})

Resources