Although I delete the data, I cannot see it being deleted unless I refresh the page - node.js

When I click it, it adds the data, but when I refresh the page, I can see that it was added.
Deleting like this is doing the same problem. I delete, but I can only see that when I refresh the page, it is deleted. How can I solve this situation?
app.component.ts
constructor(private srv: UserServiceService) {}
users: any = [];
checkForm: any;
name: FormControl;
surname: FormControl;
age: FormControl;
async ngOnInit() {
(this.name = new FormControl(
"",
Validators.compose([Validators.required])
)),
(this.surname = new FormControl(
"",
Validators.compose([Validators.required])
)),
(this.age = new FormControl(
null,
Validators.compose([Validators.required])
));
this.getAllUsers();
}
async getAllUsers() {
await this.srv.allUsers().subscribe(val => {
this.users = val;
});
}
addUserFunction() {
this.srv
.addUserService(this.name, this.surname, this.age)
.subscribe(val => {
console.log("val: ", val);
});
this.name.reset();
this.surname.reset();
this.age.reset();
}
async deleteUser(id) {
await this.srv.deleteUserService(id).subscribe(user => {
console.log(user);
});
}
user-service.service.ts
export class UserServiceService {
constructor(private http: HttpClient) {}
allUsers() {
return this.http.get("http://localhost:3000/get_users");
}
addUserService(name, surname, age) {
return this.http.post("http://localhost:3000/add_user", {
name: name,
surname: surname,
age: age
});
}
deleteUserService(id) {
return this.http.delete("http://localhost:3000/delete_user/" + id);
}
}

On successful delete you can filter your user if you don't want to go to the server to fetch a fresh list of users like this:
this.users = this.users.filter(function(index) {
return this.users.id== index;
});
So you can put this to your delete method in subscribe.
Also you can use the same approach on create, just put new user to the list, or fetch fresh ones from the server.
I would suggest that in your create method you return new user which is added to DB and put that object in your array on client side so you can have full object from server in one call.

Refresh the data by calling the getAllUsers() method in your component again after deleting/creating a user. Since ngOnInit() only gets called one time after your component is created.

Related

Cancel data insert inside beforeInsert event if it already exists in table

There is a need to insert multiple rows in a table. I am using TypeOrm which has .save() method.
.save() method is used to insert data in bulk, and it checks for the inserting primary key ID. If they exist it updates, otherwise inserts.
I want to do the checking on some other field shortLInk. Which is not possible with .save()
So I tried to do inside beforeInsert() event, things are fine but I need to cancel the isnertions if row is find.
Is there any way to achieve it? I couldn't find anything in documentation.
I can throw an error inside beforeInsert() but it will cancel whole insertions.
async shortLinks(links: Array<string>): Promise<Array<QuickLinkDto>> {
const quickLinks: Array<QuickLinkDto> = links.map((link) => ({
actualLink: link,
}));
return this.quickLinkRepository.save(quickLinks, {});
}
#Injectable()
export class QuickLinkSubscriber
implements EntitySubscriberInterface<QuickLink>
{
constructor(
datasource: DataSource,
#InjectRepository(QuickLink)
private readonly quickLinkRepository: Repository<QuickLink>,
) {
datasource.subscribers.push(this);
}
listenTo() {
return QuickLink;
}
async beforeInsert(event: InsertEvent<QuickLink>) {
const shortLink = await getShortLink(event.entity.actualLink);
const linkExists = await this.quickLinkRepository.findOne({
where: {
shortLink,
},
});
if (linkExists) {
// Discard the insertion if the row already exists
return delete event.entity; // throws error
}
event.entity.shortLink = shortLink;
}
}
When you use a transaction, all the operations are atomic, meaning either all of them are executed or none of them are. you can check for the existence of the shortLink before the insert and if it exists, you can cancel the whole transaction.
async shortLinks(links: Array<string>): Promise<Array<QuickLinkDto>> {
const quickLinks: Array<QuickLinkDto> = links.map((link) => ({
actualLink: link,
}));
const queryRunner = this.quickLinkRepository.manager.connection.createQueryRunner();
try {
await queryRunner.startTransaction();
const result = await this.quickLinkRepository.save(quickLinks, {});
await queryRunner.commitTransaction();
return result;
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
#Injectable()
export class QuickLinkSubscriber
implements EntitySubscriberInterface<QuickLink>
{
constructor(
datasource: DataSource,
#InjectRepository(QuickLink)
private readonly quickLinkRepository: Repository<QuickLink>,
) {
datasource.subscribers.push(this);
}
listenTo() {
return QuickLink;
}
async beforeInsert(event: InsertEvent<QuickLink>) {
const shortLink = await getShortLink(event.entity.actualLink);
const linkExists = await this.quickLinkRepository.findOne({
where: {
shortLink,
},
});
if (linkExists) {
// Discard the insertion if the row already exists
throw new Error('The short link already exists');
}
event.entity.shortLink = shortLink;
}
}

Repeating a dialog step based on validation

I'm currently building a provisioning bot using v4 of the Bot Framework and I've integrated it with the Microsoft Graph.
The Microsoft Graph is being used to validate user inputs, so in this scenario, it's checking to see if the group name already exists. However, the issue I'm running into is getting the bot to repeat the previous step if the validation finds the group exists.
I've read through the forum and seen a number of solutions, particularly, I have come across the step.activeDialog.state['stepIndex']-2 approach, but have been unable to get it to work. Is this a viable solution for going back a step in NodeJS or should I be looking at another approach?
async nameStep(step) {
// User selected a group type and now is required to enter the name of the group
step.values.sitetype = step.result.value;
return await step.prompt(NAME_PROMPT, 'What do you want to name it');
}
async ownerStep(step) {
// Retrieve the value from the previous step and check against the Microsoft Graph to see if the name has been used previously
step.values.name = step.result;
const getToken =
await axios.post(TOKEN_ENDPOINT, qs.stringify(postData))
.then(response => {
return {
headers: {
'Authorization': 'Bearer ' + response.data.access_token
}
}
})
.catch(error => {
console.log(error);
});
const graphCall =
await axios.get("https://graph.microsoft.com/v1.0/groups?$filter=startswith(displayName,'" + `${step.result}` + "')", getToken)
.then((response) => {
if (response.data.value[0] != null) {
return true;
}
})
.catch((error) => {
console.log(error);
})
if (!graphCall) {
return await step.prompt(NAME_PROMPT, 'What is your email address');
} else {
await step.context.sendActivity("Group already exists");
return await step.activeDialog.state['stepIndex']-2
}
}
Thanking you in advance
You can achieve this by use of a component dialog. Essentially, you extrapolate the steps you would like to repeat into a separate dialog that is called only from within the current (parent) dialog. In the parent, you institute your checks. When a check fails, the component dialog is called again. If it succeeds, the parent dialog continues on.
In the code below, my parent dialog immediately calls the component dialog for a first pass thru presenting the user with two options. Each will send a pre-determined text value which is checked to see if a LUIS intent exists for it.
The first option, "Hello", will succeed with an intent having been found. It then restarts the parent dialog. The parent dialog starts with the text "You have a choice to make in life..." which will re-display as the parent dialog begins again.
The second option will fail and returns the user to the component dialog to try again. The component dialog starts with "Text me something! I'll see if my maker setup a LUIS intent for it." This text will display when either button is clicked because the component dialog is run in both instances. However, only this text will display when LUIS fails to find an intent and restarts the component dialog.
Side note - the parent dialog in this example is, in fact, a component dialog to my main dialog which is why it is exported at the end. So, yes, you can have component dialogs within component dialogs.
Parent Dialog:
const { ComponentDialog, WaterfallDialog } = require('botbuilder-dialogs');
const { LuisRecognizer } = require('botbuilder-ai');
const { ChoiceDialogSub, CHOICE_DIALOG_SUB } = require('./choiceDialog_Sub');
const CHOICE_DIALOG = 'choiceDialog';
class ChoiceDialog extends ComponentDialog {
constructor(id) {
super(id);
this.addDialog(new ChoiceDialogSub(CHOICE_DIALOG_SUB));
this.addDialog(new WaterfallDialog(CHOICE_DIALOG, [
this.welcomeStep.bind(this),
this.choiceLuisStep.bind(this)
]));
this.initialDialogId = CHOICE_DIALOG;
try {
this.recognizer = new LuisRecognizer({
applicationId: process.env.LuisAppId,
endpointKey: process.env.LuisAPIKey,
endpoint: `https://${ process.env.LuisAPIHostName }`
}, {}, true);
} catch (err) {
console.warn(`LUIS Exception: ${ err } Check your LUIS configuration`);
}
}
async welcomeStep(stepContext) {
await stepContext.context.sendActivity('You have a choice to make in life...');
return await stepContext.beginDialog(CHOICE_DIALOG_SUB);
}
async choiceLuisStep(stepContext) {
if (stepContext.context.activity.text) {
const stepResults = stepContext.context.activity.text;
const recognizerResult = await this.recognizer.recognize(stepContext.context);
const intent = await LuisRecognizer.topIntent(recognizerResult);
if (intent === 'Greeting') {
await stepContext.context.sendActivity(`'${ stepResults }' identified in the {${ intent }} intent.`);
return await stepContext.beginDialog(CHOICE_DIALOG);
} else {
await stepContext.context.sendActivity(`No LUIS intent was found for '${ stepResults }'.`);
return await stepContext.beginDialog(CHOICE_DIALOG_SUB);
}
} else {
await stepContext.context.sendActivity('I need text, fool!');
return await stepContext.next();
}
}
}
module.exports.ChoiceDialog = ChoiceDialog;
module.exports.CHOICE_DIALOG = CHOICE_DIALOG;
Component Dialog:
const { ChoicePrompt, ChoiceFactory, ComponentDialog, WaterfallDialog } = require('botbuilder-dialogs');
const CHOICE_DIALOG_SUB = 'choiceDialogSub';
const CHOICE_DIALOG_SUB_PROMPT = 'choicePromptSub';
class ChoiceDialogSub extends ComponentDialog {
constructor(id) {
super(id);
this.addDialog(new ChoicePrompt(CHOICE_DIALOG_SUB_PROMPT))
.addDialog(new WaterfallDialog(CHOICE_DIALOG_SUB, [
this.choiceStep.bind(this)
]));
this.initialDialogId = CHOICE_DIALOG_SUB;
}
async choiceStep(stepContext) {
const choices = ['Hello', 'No soup for you!'];
return await stepContext.prompt(CHOICE_DIALOG_SUB_PROMPT, {
prompt: "Text me something! I'll see if my maker setup a LUIS intent for it.",
choices: ChoiceFactory.toChoices(choices)
});
}
}
module.exports.ChoiceDialogSub = ChoiceDialogSub;
module.exports.CHOICE_DIALOG_SUB = CHOICE_DIALOG_SUB;
Hope of help!

Performing a fetch request only on state update

I'm new to React and I'm trying to figure out how to work with fetch correctly.
I have a React component that I'd like to update from a remote server whenever its parent's state updated.
i.e - parent's state changed -> myComponent calls remote server and re-renders itself.
I've tried the following:
If I only perform the .fetch call on componentDidMount, it disregards any state updates.
If I perform the .fetch call on componentDidUpdate as well it calls the server endlessly (I assume because of some update-render loop)
I have tried using the componentWillReceiveProps function, and it works, but I understand it's now deprecated.
How can I achieve this kind of behavior without componentWillReceiveProps ?
class myComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
images: []
};
}
componentDidMount() {
let server = "somethingserver.html";
fetch(server)
.then(res => {
if (res.ok) {
return res.json();
}
else {
console.log(res);
throw new Error(res.statusText);
}
})
.then(
(result) => {
this.setState({
images: result.items
});
}
).catch(error => console.log(error));
}
componentWillReceiveProps(nextprops) {
if (this.state !== nextprops.state) {
//same as componentDidMount
}
}
render() {
return (
<Gallery images={this.state.images} enableImageSelection={false} />
);
}
}
Given our conversation in the comments I can only assume that your search term is in a parent component. So what I recommend you to do is pass it to this component as a prop so you can do the following in your componentDid update:
componentDidUpdate(prevProps) {
const { searchTerm: previousSearch } = prevProps;
const { searchTerm } = this.props;
if (searchTerm !== previousSearch) fetch() ....
}
You can use getDerivedStateFromProps. It's the updated version of componentWillReceiveProps.
You should also read this, though: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
Using props to update internal state in a component can lead to complex bugs and there are often better solutions.

NodeJS: how to implement repository pattern

I would like to implement the Repository pattern in my NodeJS app, but I'm running into troubles with circular requires (I guess...).
How I'm trying to implement it:
PersonRepository class with methods: getAll, getById, create, update, delete
Person class with methods: init, createAccount, showRelations, addRelation,
First of all: Is my repository pattern design correct?
My classes:
personRepository.js
const PersonModel = require('./model');
const Person = require('./person');
class PersonRepository {
constructor() {
this._persons = new Set();
}
getAll( cb ) { // To Do: convert to promise
let results = new Set();
PersonModel.find({}, 'firstName lastName', (err, people) => {
if (err) {
console.error(err);
}
people.forEach((person, index) => {
let foundPerson = new Person(person._id.toString(), person.firstName, person.lastName, person.email, person.birthday);
results.add(foundPerson);
});
this._persons = results;
if (cb) cb(this._persons);
});
}
getById(id) {
return PersonModel.findOne({ _id: id });
}
getByEmail(email) {
throw new Error("Method not implemented");
}
create( person ) {
throw new Error("Method not implemented");
}
update ( person ) {
throw new Error("Method not implemented");
}
delete ( person ) {
throw new Error("Method not implemented");
}
}
module.exports = new PersonRepository();
person.js
const PersonModel = require('./model');
const personRepository = require('./personRepository');
class Person {
constructor(personId, first, last, email, birthday) {
this._id = personId ? personId : undefined;
this._firstName = first ? first : undefined;
this._lastName = last ? last : undefined;
this._email = email ? email : undefined;
this._birthday = birthday ? new Date(birthday) : undefined;
this._relations = new Map();
}
init() { // Get all data from database
personRepository.getById(this._id)
.then(console.log)
.catch(console.error);
}
}
module.exports = Person;
tests.js
console.log("--- GET ALL : results--- ");
personRepository.getAll( (persons) => {
for (let person of persons) {
person.loadAllData()
.then(() => {
console.log(person);
})
.catch((e) => {
console.log(e);
});
}
});
console.log("--- INIT : results--- ");
var personInit = new Person("59c18a9029ef510012312995");
console.log("before init");
console.log(personInit);
personInit.init();
console.log("after init");
console.log(personInit);
Problem:
When running the "Get all" test (without the INIT tests), it works.
When I add the INIT tests, I get the error:
personRepository.getById(this._id)
^
TypeError: personRepository.getById is not a function
at Person.init
How can I prevent this from happening?
- Change the way I require my modules?
- Change my design? (eg. don't require Person class in personRepository and just create a Set of ids in "getAll" instead of a Set of persons)
- Other ideas?
Thanks for helping me! I'm trying to solve this for hours now...
Solved it myself. The problem was a circular dependency between the 2 modules. Problem is fixed by moving the requires after the module.exports.
Reference: https://coderwall.com/p/myzvmg/circular-dependencies-in-node-js

Why can I not call upon the property of this object? (Angular, MongoDB)

I am making an angular application which uses a MongoDB database and NodeJS server.
The idea is that I make an application which for now only has a list of posts and beside that the detailed-post. The components are nicely standing next to eachother and working but I have one problem. When I try to retrieve a single post I can see via console.dir(post) that all is good and the object has been transmitted to the angular app. The problem is that when I try to use post.content I get an undefined message.
I have searched for hours but can not seem to find the cause of this. I would greatly appreciate any help you can give me. Beneath here is all the information, if you need to see something else, please tell me.
Thanks in advance.
This is the post-detail.component.html where I want to display the data.
<div class="row">
<div class="col-xs-12">
<p>Content:</p>
<h1>{{ post.content }}</h1>
</div>
</div>
The detail.ts file (I left out the imports)
#Component({
selector: 'app-post-detail',
templateUrl: './post-detail.component.html',
styleUrls: ['./post-detail.component.css']
})
export class PostDetailComponent implements OnInit {
post: Post = new Post();
id: string;
constructor(private postService: PostService,
private route: ActivatedRoute,
private router: Router) {
}
ngOnInit() {
this.route.params
.subscribe(
(params: Params) => {
this.id = params['id'];
this.postService.getPost(this.id).then(res => {
console.dir(res);
console.dir(res.content);
this.post = res;
});
}
);
}
}
The post.service.ts which I am using to retrieve the actual data:
#Injectable()
export class PostService {
postChanged = new Subject<Post[]>();
private headers = new Headers({'Content-Type': 'application/json'});
private serverUrl = environment.serverUrl + '/blogPosts/'; // URL to web api
private posts: Post[];
constructor(private http: Http) {
}
//this one DOES work
getPosts() {
console.log('Fetching BlogPosts from database.')
return this.http.get(this.serverUrl, {headers: this.headers})
.toPromise()
.then(response => {
this.posts = response.json() as Post[];
return response.json() as Post[];
})
.catch(error => {
return error;
});
}
getPost(index: string) {
console.log('Fetching individual BlogPost from database.');
console.log('index' + index);
if (index == null) {
console.log('null');
return null;
}
return this.http.get(this.serverUrl + index, {headers: this.headers})
.toPromise()
.then(response => {
console.dir(response.json().content);
console.dir(response.json());
return response.json() as Post;
})
.catch(error => {
return this.handleError(error);
});
}
}
The Post model:
export class Post {
private id: string;
private _content: string;
constructor(values: Object = {}) {
Object.assign(this, values);
}
public get _id(): string {
return this.id;
}
public set _id(n: string) {
this.id = n;
}
public get content(): string {
return this._content;
}
public set content(n: string) {
this._content = n;
}
}
And I added in the Postman GET /blogPost/id and the console log as images.
Thanks!
Console log
Postman GET route
I might be wrong but can you please change the _content to content everywhere in the service ?
Edit: are you sure the this.id is correct when you call the service method ? cause if it is null or undefined then return null will be executed.
Another note is that in Postman i see the response is an array of objects (one object) at this example. Can you try this.post = res[0]; in the component ?
return response.json() as Post;
In post.service.ts should be:
return response.json()[0] as Post;
I did not see that the object was wrapped in an array, by accessing it I was able to get it out and use it.

Resources