Im currently working in a project that uses the Spartacus 3.2.2 and SAP Commerce 2011 with B2C accelerator. The project doesn't follow the traditional shopping website but leverages the functionality of Spartacus and SAP Commerce for its own purposes. We have a single page guest checkout flow where the Delivery Address, Payment Details and Delivery Mode gets set with the cart when an angular component loads.
The context is that lets assume a user has a form where they enter some information like email, and some other details and click next. A cart gets generated with a sample product getting added to it and the email gets associated. The users get redirected to a page to review the information that they want to submit and this page is the single page guest checkout. When this page loads, the payment details, delivery address and delivery mode get set behind the scenes and the user will not notice anything. They click submit and they create an order behind the scenes, the frontend will show something else user when they land on the confirmation page.
The issue is that when the user submit the information after reviewing it, the order call fails and we get a "delivery mode not set" and it is INCONSISTENT.
Here is a sample code that we use for the single page guest checkout:
#Component({
selector: "review-details",
templateUrl: "./review-details.component.html",
host: { class: "template-component" },
})
export class ReviewDetailsComponent implements OnInit, OnDestroy, AfterViewInit {
hasSetAddress: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
hasSetDeliveryMode: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
hasSetPaymentDetails: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
subscriptions:any = [];
ngOnInit() {
// Just an example address. A proper valid dummy address and region is used for our project.
let address: Address = {
firstName: "No Name",
lastName: "No Name",
email: "NoName#noname.com",
line1: "XYZ Mason Street",
line2: "",
town: "yolotown",
postalCode: "12345",
country: { isocode: "US" },
defaultAddress: false,
region: {
countryIso: "US",
isocode: "US-CA",
isocodeShort: "CA",
name: "California",
},
titleCode: "",
};
let paymentDetails: PaymentDetails = {
cardNumber: "4111111111111111",
expiryMonth: "12",
expiryYear: "2025",
billingAddress: address,
cvn: "123",
accountHolderName: "No Name",
cardType: {
code: "visa",
name: "Visa",
},
defaultPayment: false,
saved: false,
};
}
this.subscriptions = this.subscriptions.concat(
{
key: 'setAddress',
value: this.checkoutDeliveryService.getDeliveryAddress().subscribe((addr: Address) => {
if (_isNil(addr) || (!_isNil(addr) && _isEmpty(addr))) {
this.checkoutDeliveryService.createAndSetAddress(address);
} else {
this.hasSetAddress.next(true);
}
})
},
{
key: 'setDeliveryModeStatus',
value: this.checkoutDeliveryService.getSupportedDeliveryModes().pipe(
withLatestFrom(
this.checkoutDeliveryService
.getSelectedDeliveryMode()
.pipe(map((deliveryMode: DeliveryMode) => deliveryMode && deliveryMode.code ? deliveryMode.code : null))
)
).subscribe(([deliveryModes, code]: [DeliveryMode[], string]) => {
if (_isNil(code)) {
if (!_isNil(deliveryModes) && !_isEmpty(deliveryModes)) {
code = this.checkoutConfigService.getPreferredDeliveryMode(deliveryModes);
if (code) {
this.checkoutDeliveryService.setDeliveryMode(code);
}
}
} else {
this.hasSetDeliveryMode.next(true);
}
})
},
{
key: 'setPaymentDetails',
value: this.checkoutPaymentService.getPaymentDetails().subscribe((paymentInfo: PaymentDetails) => {
if (_isNil(paymentInfo) || (!_isNil(paymentInfo) && _isEmpty(paymentInfo))) {
this.checkoutPaymentService.createPaymentDetails(paymentDetails);
} else {
this.checkoutPaymentService.paymentProcessSuccess();
this.hasSetPaymentDetails.next(true);
}
})
},
{
key: 'placeOrder',
value: this.checkoutService
.getOrderDetails()
.pipe(filter(order => Object.keys(order).length !== 0))
.subscribe(() => {
this.routingService.go({ cxRoute: 'orderConfirmation' });
})
}
)
}
So now the questions are:
how do we even find the root cause to this "delivery mode not set" when it is inconsistent? To give more context, the request calls for the payments, address and delivery mode are getting made correctly but when the final cart object gets returned after the requests are made, we don't have the delivery cost getting set sometimes.
Is there a way to optimize the code to rule out any race conditions that may happen? Considering that all the operations to add the payment details, address, and delivery mode are set asynchronously for the same cart.
Any help is appreciated and even optimization ideas are welcome.
Thank you
References:
Spartacus Checkout guide: https://sap.github.io/spartacus-docs/3.x/extending-checkout/#combining-checkout-steps
please refer to this SAP note for an explanation on multiple updates to checkout information using OCC API calls:
https://launchpad.support.sap.com/#/notes/2998330.
Summary: to perform various updates for checkout at the same time, you need to use a single API call. The SAP note provides an example extension you can use for this scenario.
Best regards,
Jerry
Here is the answer to my own question, thanks to the SAP Support and the Spartacus Development teams for helping me with this.
In addition to Jerry's answer which is more of a permanent and straight forward solution which would need to be done on both frontend and backend, here is another solution which only requires us to make changes on the frontend only.
The code can be changed in the following manner to make the calls sequentially load the details on the cart.
#Component({
selector: "review-details",
templateUrl: "./review-details.component.html",
host: { class: "template-component" },
})
export class ReviewDetailsComponent implements OnInit, OnDestroy, AfterViewInit {
hasSetAddress: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
hasSetDeliveryMode: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
hasSetPaymentDetails: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
subscriptions: any = [];
// Just an example address. A proper valid dummy address and region is used for our project.
private address: Address = {
firstName: "No Name",
lastName: "No Name",
email: "NoName#noname.com",
line1: "XYZ Mason Street",
line2: "",
town: "yolotown",
postalCode: "12345",
country: { isocode: "US" },
defaultAddress: false,
region: {
countryIso: "US",
isocode: "US-CA",
isocodeShort: "CA",
name: "California",
},
titleCode: "",
}
private paymentDetails: PaymentDetails = {
cardNumber: "4111111111111111",
expiryMonth: "12",
expiryYear: "2025",
billingAddress: address,
cvn: "123",
accountHolderName: "No Name",
cardType: {
code: "visa",
name: "Visa",
},
defaultPayment: false,
saved: false,
}
private address$: Observable<Address> = this.checkoutDeliveryService.getDeliveryAddress().pipe(
tap((addr: Address) => {
if (_isNil(addr) || (!_isNil(addr) && _isEmpty(addr))) {
this.checkoutDeliveryService.createAndSetAddress(this.address);
}
}),
filter((addr) => (!_isNil(addr) && !_isEmpty(addr)))
);
private deliveryMode$: Observable<string> = this.checkoutDeliveryService.getSupportedDeliveryModes().pipe(
filter((deliveryModes: DeliveryMode[]) => deliveryModes?.length !== 0),
withLatestFrom(
this.checkoutDeliveryService.getSelectedDeliveryMode()
.pipe(map((selectedDeliveryMode: DeliveryMode) => selectedDeliveryMode?.code))
),
map(([deliveryModes, code]: [DeliveryMode[], string]) => {
return code
? code
: this.checkoutConfigService.getPreferredDeliveryMode(deliveryModes);
}),
tap((code) => {
if (code) {
this.checkoutDeliveryService.setDeliveryMode(code);
}
}),
filter((code) => !!code)
);
private payment$: Observable<PaymentDetails> = this.checkoutPaymentService.getPaymentDetails().pipe(
tap((paymentInfo: PaymentDetails) => {
if (_isNil(paymentInfo) || (!_isNil(paymentInfo) && _isEmpty(paymentInfo))) {
this.checkoutPaymentService.createPaymentDetails(this.paymentDetails);
}
}),
filter((paymentInfo) => (!_isNil(paymentInfo) && !_isEmpty(paymentInfo)))
);
private setCartDetails$: Observable<boolean> = this.address$.pipe(
take(1),
map((_) => this.deliveryMode$.pipe(take(1))),
concatAll(),
map((_) => this.payment$.pipe(take(1))),
concatAll(),
map((_) => {
this.checkoutPaymentService.paymentProcessSuccess();
this.hasSetAddress.next(true);
this.hasSetDeliveryMode.next(true);
this.hasSetPaymentDetails.next(true);
return true;
}));
ngOnInit() {
this.subscriptions = this.subscriptions.concat(
{
key: "setCartDetails",
value: this.setCartDetails$.subscribe((status: boolean) => console.log(status))
},
{
key: 'placeOrder',
value: this.checkoutService
.getOrderDetails()
.pipe(filter(order => Object.keys(order).length !== 0))
.subscribe(() => {
this.routingService.go({ cxRoute: 'orderConfirmation' });
})
}
)
}
}
Related
I have the following Firebase Function:
exports.updateStripeCustomer = functions.region('europe-west3')
.firestore
.document('users/{userId}')
.onUpdate( async (change, context) => {
const oldValue = change.before.data();
const newValue = change.after.data();
if( JSON.stringify(newValue.adresse) != JSON.stringify(oldValue.adresse) ) {
const user = await admin.auth().getUser(change.after.id)
.then((user) => {
return user.displayName
})
const stripe = Stripe(<api-key>)
const customer = await stripe.customers.update(oldValue.stripe_id,
{
shipping: {
address: {
city: newValue.ort,
postal_code: newValue.plz,
line1: newValue.strasse,
line2: newValue.hausnum
},
name: user
},
}
);
return customer
}
return 'no Data changed'
})
The function itself works - only the format for passing the shipping information is not clear to me and seems wrong. The example from the Stripe Api documentation is not quite clear to me.
Stripe return the following error:
parameter_unknown - shipping[0]
Received unknown parameter: shipping[0]
Complete LOG Error:
{
"shipping": {
"0": {
"name": "Testi Tester"
}
}
}
-------------
Response-Text
{
"error": {
"code": "parameter_unknown",
"doc_url": "https://stripe.com/docs/error-codes/parameter-unknown",
"message": "Received unknown parameter: shipping[0]",
"param": "shipping[0]",
"type": "invalid_request_error"
}
}
Many Thanks for Help !
Your parameters appear to conform to the API docs for shipping (link). The error structure suggests that your shipping object is being interpreted as an array, which means something isn't being stringified properly for the request.
My hunch that that this is related to your name: user child parameter. This should just be a string, but based on the line user.displayName earlier in your snippet it appears user is a complex object. Did you mean to use the same user.displayName in the update request?
I'd suggest you try putting in a temporary test value name: 'test name' to see if that resolves the issue, then figure out which attribute from your user object you want to use.
I am working with xstate with Nextjs. Now I am stuck somewhere.
import { assign, createMachine, interpret } from "xstate";
export interface toggleAuth {
isAuthenticated: boolean;
user: {
name: string | undefined;
};
}
// console.log(getCachedData());
export const authMachine = createMachine<toggleAuth>({
id: "auth",
initial: "unauthenticated",
context: {
isAuthenticated: false,
user: {
name: undefined,
},
},
states: {
authenticated: {
on: {
toggle: {
target: "unauthenticated",
},
},
entry: assign({
user: (ctx) => (ctx.user = { name: "Pranta" }),
isAuthenticated: (ctx) => (ctx.isAuthenticated = true),
}),
},
unauthenticated: {
on: {
toggle: {
target: "authenticated",
},
},
entry: assign({
user: (ctx) => (ctx.user = { name: undefined }),
isAuthenticated: (ctx) => (ctx.isAuthenticated = false),
}),
},
},
});
const service = interpret(authMachine);
service.onTransition((state) => console.log(state));
So I was watching the docs. According to them, whenever I transition from unauthenticated to authenticated and authenticated to unauthenticated, it should console log it for me. But it doesn't. It does only one time. What's happening here. Also, is it okay to define my machine like this? Thanks in advance.
It's not logging because you're not changing state; no event is ever being sent.
Please re-read the documentation on assigning to context - you are mutating context instead of assigning new values; the assigners should always be pure.
If you want to see the state change, you need to send a toggle event in this case:
service.send('toggle');
Also, there is no need for isAuthenticated; this is redundant, since that state is represented by the finite state (state.value) of your machine.
I am working on creating a RESTlet to load paginated customer records. One of the thing i need is the customer's defaultaddress. This field is available when I load a single customer like this:
customer = record.load({
type: record.Type.CUSTOMER,
id: context.id, // e.g. 1234
isDynamic: false
});
However, when I try to load all customers with pagination like this:
define(['N/record', 'N/search'], function(record, search) {
var currencies = {};
function getClients(context) {
var mySearch = search.create({
type: search.Type.CUSTOMER,
columns: [
{ name: 'companyname' },
{ name: 'vatregnumber' },
{ name: 'lastmodifieddate' },
{ name: 'currency' },
{ name: 'email' },
{ name: 'phone' },
{ name: 'defaultaddress' }
]
});
var searchResult = mySearch.run().getRange({
start: context.start || 0,
end: context.end || 100
});
var results = [];
for (var i = 0; i < searchResult.length; i++) {
results.push({
tax_number: searchResult[i].getValue({ name: 'vatregnumber' }),
name: searchResult[i].getValue({ name: 'companyname' }),
// snipped...
});
}
return results;
}
function loadCurrencyName(id) {
return record.load({
type: record.Type.CURRENCY,
id: id,
isDynamic: false
}).name;
}
return {
get: getClients
}
});
and execute the rest api call to the above RESETlet script; I get the following error:
{
"type":"error.SuiteScriptError",
"name":"SSS_INVALID_SRCH_COL",
"message":"An nlobjSearchColumn contains an invalid column, or is not in proper syntax: defaultaddress.",
"stack":[ ... snipped ... ],
"cause":{ ... snipped ... },
"id":"",
"notifyOff":false
}
Any idea how to best to load the default address of the customer, whilst loading all customers using the paged search feature?
{defaultaddress} is calculated when the customer record is loaded - it's not a stored field and is not available for saved searches. As the field help says, it's simply the default billing address and changes automatically according to what address in the address subtab you have checked 'Default Billing" on.
To work around this and display what you're looking for, you can simply replace defaultaddress with billaddress.
I am trying to configure stripe.accounts.create({}) for Stripe custom. My goal here is to create everything in one form so the user fulfills all of the information requirements for their stripe account to transact after the form is compete. When testing the current code using the credit card number Stripe recommended, I am getting the error that is displayed after the following code block. I am wondering if there is a tokenization process that I am missing that isn't referenced in the stripe create account docs. This is my current post method
var knex = require("../models/knex"),
express = require('express'),
middleware = require("../middleware/index"),
stripe = require("stripe")("sk_test_VALUEOFMYTESTKEY"),
router = express.Router({mergeParams:true});
router.post("/formuser",function(req,res){
console.log(req.user[0].user_id);
knex("users.user").select("*").where("user_id",req.user[0].user_id)
.then((user) => {
var today = new Date(Date.now()).toLocaleString();
var accountType = String(req.body.accountType).toLowerCase();
var checkIfCard = accountType=="card";
console.log(req.body.accountType,checkIfCard,String(req.body.cardNumber));
var ip = req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress;
console.log(ip);
if(!checkIfCard){
stripe.accounts.create({
email: user.email,
country: "US",
type: "custom",
//Required fields for Custom via... https://stripe.com/docs/connect/required-verification-information
metadata: {
"external_account": {
"object": "bank_account",
"exp_month": req.body.cardExpirationMonth,
"exp_year": req.body.cardExpirationYear,// : null,
"number": req.body.bankNumber,// : null,
}, //external account info... https://stripe.com/docs/api#account_create_bank_account
"city": req.body.city,
"legal_entity.adress.line1": req.body.streetAddress,
"legal_entity.address.postal_code": req.body.zipCode,
"legal_entity.address.state": req.body.state,
"legal_entity.dob.day": req.body.birthDay,
"legal_entity.dob.month": req.body.birthMonth,
"legal_entity.dob.year": req.body.birthYear,
"legal_entity.first_name": req.body.firstName,
"legal_entity.last_name": req.body.lastName,
"legal_entity.ssn_last_4": req.body.ssn_last_4,
"tos_acceptance.date": today,
"tos_acceptance.ip": ip,
}
}).then((acct) => {
res.redirect("/");
})
.catch((e) => {
console.log(e);
});
} else {
stripe.accounts.create({
email: user.email,
country: "US",
type: "custom",
//Required fields for Custom via... https://stripe.com/docs/connect/required-verification-information
metadata: {
"external_account": {
"object": "card", //bank account or cc or dc...
"card": req.body.cardNumber.toString(),
"cvc" : req.body.cvc.toString(),
"currency" : "usd",// : null
}, //external account info... https://stripe.com/docs/api#account_create_bank_account
"city": req.body.city,
"legal_entity.adress.line1": req.body.streetAddress,
"legal_entity.address.postal_code": req.body.zipCode,
"legal_entity.address.state": req.body.state,
"legal_entity.dob.day": req.body.birthDay,
"legal_entity.dob.month": req.body.birthMonth,
"legal_entity.dob.year": req.body.birthYear,
"legal_entity.first_name": req.body.firstName,
"legal_entity.last_name": req.body.lastName,
"legal_entity.ssn_last_4": req.body.ssn_last_4,
"tos_acceptance.date": today,
"tos_acceptance.ip": ip,
}
}).then((acct) => {
res.redirect("/");
})
.catch((e) => {
console.log(e);
});
}});
});
When I enter in the credit card information that Stripe recommends to test, I get the following error
{ [Error: Invalid val: {"object"=>"card", "card"=>"4242 4242 4242 4242", "cvc"=>"111", "currency"=>"usd"} must be a string under 500 characters]
type: 'StripeInvalidRequestError',
stack: 'Error: Invalid val: {"object"=>"card", "card"=>"4242 4242 4242 4242", "cvc"=>"111", "currency"=>"usd"} must be a string under 500 character
when I expected a user to be created.
EDIT: I removed some of the knex database code in this post to shorten it's length as it is not relevant to the current error. The current error is specifically from Stripe's promise.
Your code is trying to pass bank account details in external_account but also passing card data at the same time. This is unlikely to be what you want.
On top of this, you should not be passing this information server-side at all as it's sensitive. Instead, you should be creating a token client-side. For card data, you would use Elements and for bank account data you would build your own form and tokenize with Stripe.js. Once this is done, you get a card token tok_123 or a bank account token btok_123 and can then use this server-side in the external_account parameter.
Then, you should also pass the data as nested hashes. This means that you would not pass "legal_entity.adress.line1" but instead legal_entity[address][line1]. Your code should instead look something like this:
stripe.accounts.create(
{
type: 'custom',
country: 'US',
legal_entity : {
first_name : 'john',
last_name : 'doe',
type : 'individual',
address: {
line1: 'line1',
city: 'city',
state: 'state',
postal_code: '90210',
country: 'US'
}
},
external_account: 'tok_visa_debit',
}).then((acct) => {
console.log('account: ', JSON.stringify(acct));
}).catch((e) => {
console.log(e);
});
Has any one figure out on how to load the server data from the ng2-smart table plugin of Angular2.
I have few products data that is retrieved from Node API and Im able to display the same onClick event in the browser log.
I need to display the same in this 3rd party plugins table area which they have provided in this documentation below:
Frontend : https://akveo.github.io/ng2-smart-table/#/examples/populate-from-server
Under "Server Data Source Example"
Code: https://github.com/akveo/ng2-smart-table/blob/master/src/app/pages/examples/server/advanced-example-server.component.ts
Accordingly i have configured in my code as below:
blank-page.component.ts
import { ServerDataSource } from 'ng2-smart-table';
import { Component } from '#angular/core';
import { Http } from '#angular/http';
#Component({
selector: 'advanced-example-server',
template: `
<ng2-smart-table [settings]="settings" [source]="source"></ng2-smart-table>
`,
})
export class BlankPageComponent implements OnInit {
settings = {
columns: {
id: {
title: 'ID',
},
albumId: {
title: 'Album',
},
title: {
title: 'Title',
},
url: {
title: 'Url',
},
},
};
source: ServerDataSource;
//Doubt or Problem here!!!
constructor(http: Http) {
this.source = new ServerDataSource(http, { endPoint: 'https://jsonplaceholder.typicode.com/photos' });
}
//Tried like this too (Which is not the right way of calling)
constructor(http: Http) {
this.source = new ServerDataSource(http, { endPoint: this.productService.getProductsOncategory(this.categoryid) });
}
//Dint work this too!!
constructor(http: Http) {
this.source = new ServerDataSource(http, { endPoint:'http://localhost:5000/products/getProductsOncategory ' });
}
}
Where my service.ts file is like, which actually displays the products data in my browser log which i need to show in my table data
getProductsOncategory(category_id){
let catUrl="http://localhost:5000/products/getProductsOncategory"
let headers = new Headers();
headers.append('Content-Type','application/json');
let catIdObj = JSON.stringify({category_id:category_id})
console.log(catIdObj)
return this.http.post(catUrl,catIdObj,{headers:headers})
.map((response:Response)=>response.json())
.do(data=>console.log(JSON.stringify(data)))
.catch(this.handleError);
}
Error if i use my projects url in endpoint
Error: Uncaught (in promise): Error: Data must be an array. Please check that data extracted from the server response by the key '' exists and is array.
This is what i did and worked perfect for me, i used smart table server side paging, but build my own filter for custom filtration experience.
1- Define Server Data Source
source: ServerDataSource;
2- set it in constructor with config object
this.source = new ServerDataSource(http,
{
endPoint: 'full-url-for-endpoint',
dataKey: 'your-list-path-from-response' for example 'data.records' ,
pagerPageKey: 'your backend param excpected for page number key',
pagerLimitKey: 'your backend param excpected for page size',
totalKey: total records returned in response path for example 'data.total',
filterFieldKey: your filter keys template should set to '#field#' if you need to send params as you set, Default is '#field#_like'
});`
3- add settings object
settings = {
actions: {
custom: [ // if you need custom actions do like that
{ name: 'view-something', title: '<i title="Exception" class="nb-alert"></i>' },
{ name: 'do-custom', title: '<i class="fa fa-pencil"></i>' }
],
add: true, //if you don't need default add button set to false
edit: true, //if you don't need default add button set to false
delete: true, //if you don't need default delete button set to false
position: 'right' // buttons position
}, // remove add , edit , delete objects if you don't use
add: {
addButtonContent: '<i class="nb-plus"></i>',
createButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>',
},
edit: {
editButtonContent: '<i class="nb-edit"></i>',
saveButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>',
},
delete: {
deleteButtonContent: '<i class="nb-trash"></i>',
confirmDelete: true,
},
pager: {
display: true // set to false if no need for pagination
},
columns: {
Id: { // set up table cols - Id is a prop name returned from backend
title: 'ID', // display name in table header
type: 'number',
filter: false // add text filter for it or not
},
Name: {
title: 'Full Name',
type: 'string',
filter: false
}
}
};
// Add Filter Data , i used a custom form binded with ngModel above table for filtration, so assume you have a model called filter which get data from external form
FilterData() {
this.source.reset(true); // reset your old filtered data
this.source.setPage(1, false); // set page to 1 to start from beginning
let filterArr = this.getFilterArray(); // add a new filter data, but be careful to not sent any empty data, as it throws an exception
if (filterArr.length)
this.source.setFilter(filterArr, false, false);
this.source.refresh(); // this will call the server with new filter and paginatio data
}
getFilterArray() { // setup new filter
let filterArray = [];
if (this.filter.id)
filterArray.push({ field: 'id', search: this.filter.id });
if (this.filter.name)
filterArray.push({ field: 'name', search: this.filter.name});
return filterArray;
}
onCustomAction(event) { // custom buttons code
switch (event.action) {
case 'view-something':
// put your code here
break;
default:
console.log('Not Implemented Action');
break;
}
}
With this example my data is resource so the datakey is set resource
find below sample code
{
source: ServerDataSource;
constructor(http: HttpClient) {
this.source = new ServerDataSource(http, { dataKey: 'resource', endPoint:'http://localhost:8080/api/v2/mysql/_table/able' })
}
You need to set the dataKey for the ServerDataSource. For example, if your JSON is { data: [...], total: .. }, you need to set dataKey = 'data'.
this worked for me on Angular 8, But Search box functionality needs to be handeled from backend (i.e: localhost:5000/session_info/Seance1?temp_like=30), so backend need to filter (temp_like = value) in database, which make search box retrive live data.
Here is the entire component with Edit and Delete, Enjoy it!
import {Component} from '#angular/core';
import {ServerDataSource} from 'ng2-smart-table';
import {HttpClient} from "#angular/common/http";
import {Setting} from "../../setting";
#Component({
selector: 'ngx-session-man',
templateUrl: './sessions-man.component.html',
styleUrls: ['./sessions-man.component.scss'],
})
export class SessionsManComponent {
settings = {
mode: 'inline',
add: {
addButtonContent: '<i class="nb-plus"></i>',
createButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>',
},
edit: {
editButtonContent: '<i class="nb-edit"></i>',
saveButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>',
confirmSave: true,
},
delete: {
deleteButtonContent: '<i class="nb-trash"></i>',
confirmDelete: true,
},
columns: {
name: {
title: 'Séance',
type: 'string',
},
start: {
title: 'Début',
type: 'any',
},
end: {
title: 'Fin',
type: 'any',
},
},
};
source: ServerDataSource;
constructor(private httpClient: HttpClient) {
this.source = new ServerDataSource(this.httpClient, {endPoint: Setting.baseUrl + 'all_sessions_table'});
}
onDeleteConfirm(event): void {
if (window.confirm('Are you sure you want to delete ' + event['data']['name'] + '?')) {
event.confirm.resolve();
this.httpClient.delete<any>('http://localhost:5000/del-seance/' + event['data']['name']).subscribe(
temps => {});
} else {
event.confirm.reject();
}
}
onEditConfirm(event): void {
if (window.confirm('Are you sure you want to edit ' + event['data']['name'] + '\'s name to ' + event['newData']['name'] + '?')) {
event.confirm.resolve();
this.httpClient.post<any>('http://localhost:5000/mod-seance/' + event['data']['name'] + '/' + event['newData']['name'], { title: 'Session deleted' }).subscribe(
temps => {});
} else {
event.confirm.reject();
}
}
}