Closed bklingDt closed 5 years ago
1) The RestlessService.ts file should be called players.component.ts 2) The component does not need to be imported into another component. You must import into app.module.ts (declarations and ROUTES) 3) providers: [RestlessService] - not needed, because a new instance of new RestlessService () is being created
Thank you, i am now able to get the data to load through FLASK API :)
Only issue now is that update/delete do not work, i get 405 METHOD NOT ALLOWED.
DELETE http://127.0.0.1:5000/api/customers/1 405 (METHOD NOT ALLOWED)
restless.service.ts:111 HttpErrorResponse {headers: HttpHeaders, status: 405, statusText: "METHOD NOT ALLOWED", url: "http://127.0.0.1:5000/api/customers/1", ok: false, …}error: "<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">↵<title>405 Method Not Allowed</title>↵<h1>Method Not Allowed</h1>↵<p>The method is not allowed for the requested URL.</p>↵"headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}message: "Http failure response for http://127.0.0.1:5000/api/customers/1: 405 METHOD NOT ALLOWED"name: "HttpErrorResponse"ok: falsestatus: 405statusText: "METHOD NOT ALLOWED"url: "http://127.0.0.1:5000/api/customers/1"__proto__: HttpResponseBase
The DB user the api is connected with has db_datareader, db_datawriter, db_owner, public so DB user should have sufficient rights to update/add/delete records. Is this an issue with my FLASK API setting or something in ng-crud-table i need to adjust?
Try testing the put and delete methods in restless.service.ts. Check {headers: this.headers}. Maybe you need a custom service. for example: ` this.service.put(row).then(res => {});
this.service.delete(row).then(res => {}); `
I have all of the operations working now except update (PUT).
This is the error i am getting when i try to make an update.
restless.service.ts:115
HttpErrorResponse {headers: HttpHeaders, status: 400, statusText: "BAD REQUEST", url: "http://127.0.0.1:5000/api/customers/1", ok: false, …}
error:
message: "Model does not have field '$$uid'"
__proto__: Object
headers: HttpHeaders
lazyInit: ƒ ()
lazyUpdate: null
normalizedNames: Map(0) {}
__proto__: Object
message: "Http failure response for http://127.0.0.1:5000/api/customers/1: 400 BAD REQUEST"
name: "HttpErrorResponse"
ok: false
status: 400
statusText: "BAD REQUEST"
url: "http://127.0.0.1:5000/api/customers/1"
__proto__: HttpResponseBase
push../src/ng-crud-table/services/restless.service.ts.RestlessService.handleError @ restless.service.ts:115
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:391
onInvoke @ core.js:17289
"Model does not have field '$$uid'" Need to remove extra fields
def remove_extra_keys(subject, **kwargs):
mapper = inspect(subject)
columns = [column.key for column in mapper.attrs]
for key, value in kwargs.copy().items():
if key not in columns:
kwargs.pop(key, None)
kwargs[key] = value
return kwargs
subject - is db.Model
instead
constructor(private http: HttpClient) {
this.service = new RestlessService(this.http, new NotifyService());
constructor(private http: HttpClient, private notifyService: NotifyService) {
this.service = new RestlessService(this.http, this.notifyService);
Your code to remove the extra fields, that is python and needs to be on my python code? I tried adding but does not fix problem.
#Restless.py File
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_restless import APIManager
app = Flask(__name__)
app.config.from_pyfile('config1.cfg')
db = SQLAlchemy(app)
#Define API for customers table
class customers(db.Model):
__table_args__ = {"schema":"cust"}
custID = db.Column(db.Integer, primary_key=True)
custName = db.Column(db.String(50))
businessUnit = db.Column(db.String(50))
subBusinessUnit = db.Column(db.String(50))
subject = db.Model
def remove_extra_keys(subject, **kwargs):
mapper = inspect(subject)
columns = [column.key for column in mapper.attrs]
for key, value in kwargs.copy().items():
if key not in columns:
kwargs.pop(key, None)
kwargs[key] = value
return kwargs
manager = APIManager(app, flask_sqlalchemy_db=db)
#Create the API Connections
manager.create_api(customers,methods=['GET','PUSH','POST','DELETE','PATCH', 'PUT'])
#Run App
if __name__ == "__main__":
app.run(debug=True)
When i view the request payload in console of chrome i see this weird $$UID part of the body which i did not see on POST/DELETE requests, those were just the data fields. So why would i need to add code to the python API if it seems ng-crud-table is building a bad request body when using PUT command only?
Sorry if this is such a basic question this is my first exposure to angular/JS/python.
Greatly appreciate your help!!!
Payload for a POST that was successful:
{dk: "77777TEST", custName: "TEST", pcc: "TST", gds: "SABRE", businessUnit: "NONE",…}
businessUnit: "NONE"
custName: "TEST"
dk: "77777TEST"
gds: "SABRE"
inCompleat: "0"
pcc: "TST"
subBusinessUnit: "TEST"
Payload for update (PUT) failure:```
{businessUnit: "NONE", custID: 788, custName: "TEST", dk: "77777TEST2", gds: "SABRE", inCompleat: 0,…}
$$data: {businessUnit: "NONE", custID: 788, custName: "TEST", dk: "77777TEST", gds: "SABRE", inCompleat: 0,…}
$$uid: 10
businessUnit: "NONE"
custID: 788
custName: "TEST"
dk: "77777TEST"
gds: "SABRE"
inCompleat: 0
pcc: "TST"
subBusinessUnit: "TEST"
$$index: 10
$$uid: 10
businessUnit: "NONE"
custID: 788
custName: "TEST"
dk: "77777TEST2"
gds: "SABRE"
inCompleat: 0
pcc: "TST"
subBusinessUnit: "TEST"
Not sure why this extra $$data, $$index and $$uid in the PUT request that seems to be causing the error.
There are also some other small bugs that i think are related to the API connection.
Pagination does not work, if i shut it off, i get 12 records displayed, when i try to change number of rows returned page refreshes with no changes and drop down goes back to 10. When i change to pages, 2, 3, 4, etc that works fine and displays new data.
GlobalFilter (search box) does not work. A filter icon appears on the table but it does not filter the data at all. Tried to force client side search in CdtSettings and that did not make it work either. Demo page works fine and i cannot see any obvious difference in my code. My new site files are sitting under /src/app and not /src/app/demo so maybe there is a dependency file there not setup correct?
customers.component.ts file:
import {Component} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Column, CdtSettings, DataSource, RestlessService, DataManager} from '../ng-crud-table';
import {Validators} from '../lib/validation/validators';
import { NotifyService } from 'src/lib/notify';
@Component({
selector: 'my-app',
template: `
<app-crud-table [dataManager]="dataManager"></app-crud-table>
<app-notify></app-notify>
`
})
export class CustomersComponent {
dataManager: DataManager;
service: RestlessService
constructor(private http: HttpClient, private notifyService: NotifyService) {
// YiiService | RestlessService | OrdsService | your custom service
this.service = new RestlessService(this.http, this.notifyService);
this.service.url = 'http://127.0.0.1:5000/api/customers';
this.service.primaryKeys = ['custID'];
this.dataManager = new DataManager(this.columns, this.settings, this.service);
}
columns: Column[] = [
{
title: 'custID',
name: 'custID',
sortable: true,
filter: true,
editable: false,
//frozen: true,
width: 60,
formHidden: true,
//type: 'number',
},
{
title: 'Account Number',
name: 'dk',
sortable: true,
filter: true,
editable: true,
},
{
title: 'Customer Name',
name: 'custName',
sortable: true,
filter: true,
width: 500,
//validatorFunc: Validators.get({required: true, minLength: 2, pattern: '^[a-zA-Z ]+$'}),
editable: true,
},
{
title: 'pcc',
name: 'pcc',
sortable: true,
filter: true,
//validatorFunc: Validators.get({required: true, minLength: 2, pattern: '^[a-zA-Z ]+$'}),
editable: true,
},
{
title: 'gds',
name: 'gds',
sortable: true,
filter: true,
//validatorFunc: Validators.get({required: true, minLength: 2, pattern: '^[a-zA-Z ]+$'}),
editable: true,
},
{
title: 'businessUnit',
name: 'businessUnit',
sortable: true,
filter: true,
//validatorFunc: Validators.get({required: true, minLength: 2, pattern: '^[a-zA-Z ]+$'}),
editable: true,
},
{
title: 'subBusinessUnit',
name: 'subBusinessUnit',
sortable: true,
filter: true,
//validatorFunc: Validators.get({required: true, minLength: 2, pattern: '^[a-zA-Z ]+$'}),
editable: true,
},
{
title: 'inCompleat',
name: 'inCompleat',
sortable: true,
filter: true,
//validatorFunc: Validators.get({required: true, minLength: 2, pattern: '^[a-zA-Z ]+$'}),
editable: true,
}
];
settings: CdtSettings = {
crud: true,
//tableWidth: 820,
//bodyHeight: 380,
multipleSort: true,
exportAction: true,
globalFilter: true,
clearAllFiltersIcon: true,
//filter: true,
columnToggleAction: true,
//paginator: false,
clientSide: true,
};
}
You need to modify RestlessService for your backend. It contains pagination and global search.
delete row.$$uid;
delete row.$$index;
delete row.$$data;
THANK YOU!!!!! That did the trick for fixing updates. :)
This is such a great app, thanks for your help.
clientSide - not used with the service, in the future I will delete this setting. https://github.com/mazdik/ng-crud-table#custom-service
even when i do not enable the clientSide flag the search box does not work.
<dt-toolbar [table]="table"></dt-toolbar>
<app-data-table [table]="table"></app-data-table>
app-data-table - client side app-crud-table - server side
I made some progress on the pagination issue. I made the following changes to my restless.service.ts file, and now the number of rows updates when i select a new value (10, 20, 50, etc).
However, the drop down stays stuck at 10. If i change to 20, the box displays 20 rows but drop down will still say 10, like it not saving the value last chosen, and i can never select 10 from the list.
I still can not get the global search to function though.
OLD
getItems(requestMeta: RequestMetadata): Promise<PagedResult> {
const page = requestMeta.pageMeta.currentPage;
let url = this.url;
if (page > 1) {
if (url.indexOf('?') === -1) {
url = url + '?page=' + page;
} else {
url = url + '&page=' + page;
}
}
if (this.filterObject(requestMeta)) {
url += (url.indexOf('?') === -1) ? '?' : '&';
url = url + this.filterObject(requestMeta);
}
console.log(url)
console.log(page)
console.log(requestMeta)
return this.http.get<PagedResult>(url, {headers: this.headers})
.toPromise()
.then(this.extractData)
.catch(this.handleError.bind(this));
}
NEW
getItems(requestMeta: RequestMetadata): Promise<PagedResult> {
const page = requestMeta.pageMeta.currentPage;
const perPage = requestMeta.pageMeta.perPage;
let url = this.url;
if (page > 1) {
if (url.indexOf('?') === -1) {
url = url + '?page=' + page;
} else {
url = url + '&page=' + page;
}
}
if (url.indexOf('?') === -1) {
url = url + '?results_per_page=' + perPage;
} else {
url = url + '&results_per_page=' + perPage;
}
if (this.filterObject(requestMeta)) {
url += (url.indexOf('?') === -1) ? '?' : '&';
url = url + this.filterObject(requestMeta);
}
console.log(url)
console.log(page)
console.log(requestMeta)
return this.http.get<PagedResult>(url, {headers: this.headers})
.toPromise()
.then(this.extractData)
.catch(this.handleError.bind(this));
}
OLD
getItem(row: any): Promise<any> {
const filters = {};
for (const key of this.primaryKeys) {
filters[key] = {value: row[key]};
}
const requestMeta = <RequestMetadata> {
pageMeta: {currentPage: 1},
filters: filters,
};
return this.getItems(requestMeta)
.then(data => data.items[0]);
}
NEW
getItem(row: any): Promise<any> {
const filters = {};
for (const key of this.primaryKeys) {
filters[key] = {value: row[key]};
}
const requestMeta = <RequestMetadata> {
pageMeta: {currentPage: 1, perPage: 10},
filters: filters,
};
return this.getItems(requestMeta)
.then(data => data.items[0]);
}
When i tweak the number in this part of restless.service.ts it will change the value the dropdown defaults to, which makes me thing body.limit is not being set somehow?
private extractData(res: any) {
let body = res;
const meta = {
'totalCount': body.num_results,
'perPage': body.limit || 10
};
const items = (body.objects) ? body.objects : body;
body = {'items': items, '_meta': meta};
return body;
}
I am having trouble getting the demo to connect to a FLASK API service. I replaced the data in the "players.json" file with my test data, so i know my table formatting is good because the table loads fine from the json file, it just wont connect to my api.
I created a new "RestlessService.ts" and call that from "basic-demo.components.ts", tried to follow your suggested code in the readme as best i could.
The page loads when i do "npm start" but i get a http error pop up:
basic-demo.component.ts
RestlessService.ts