Angular 11 how to pass row item from template to observable - rxjs

html:
<tr
*ngFor="let workflow of auditWorkflows"
class="border-bottom"
[rowClick]="workflow | auditWorkflowRouteNavigate"
[rowClickGate]="startAuditIfNotStarted$"
>
.ts
startAuditIfNotStarted$ = new Observable((subscriber) => {
if (this.auditInProgress) {
subscriber.next(true);
subscriber.complete();
} else {
***//Here i need to get the current row item i.e workflow.id to do some additional logic***
this.confirmDialog.confirm({
header: 'Begin audit',
message: 'Are you sure you would like to start the audit?',
acceptLabel: 'Yes',
rejectLabel: 'No',
accept: () => {
this.auditInstanceService.start(this.auditId).subscribe(() => {
this.auditInProgress = true;
subscriber.next(true);
subscriber.complete();
});
},
reject: () => {
subscriber.next(false);
subscriber.complete();
}
});
}
});
directive code block:
#Input('rowClick')
options: RouterNavigateParams;
#Input('rowClickGate')
gate$?: Observable<boolean>;
private applyGateThen(callback: () => void) {
if (this.gate$) {
this.gate$.pipe(take(1)).subscribe((allow) => {
if (allow) {
callback();
}
});
} else {
callback();
}
}
Now, in the existing code , i want to pass the 'workflow' item from *ngFor into the observable, so i can do some additional logic. If i used a method as below, the method is called so many times. Is there a better way to get hold of the row item?
[rowClickGate]="provideSub(workflow)"

Related

Skip a after hook in a Cypress test

In my Cypress config I have a hook:
//hooks.ts
after(() => {
if (Cypress.currentTest.titlePath[0] === 'Skip after') {
return;
}
cy.wait(2500);
cy.el('btnLogoutUser').should('exist').click({ force: true });
cy.url().should('contain', 'login');
cy.task('getCompany').then((data: any) => {
cy.task('cleanCompany', data.company.company_id).then((response: any) => {
cy.log(`
=================================================
Removed company with id: ${response.substring(47)}
=================================================
`);
});
});
localStorage.clear();
});
But on some tests I want to skip this hook. That's why I added the if condition.
//test.cy.ts
describe('Skip after', () => {
it('Does something', () => {
cy.el('btnCompanySettings').click({ force: true });
});
});
This works, but I would much rather add a boolean value in the describe and pass that so I can check that value. Something like:
//test.cy.ts
describe({title: 'Name of test', skipAfter: true}), () => { ... }
But the describe only takes a string value.
You can add a custom property to the configuration object in your describe method (that is the one between the suite name and the callback function). Then, you can access it from Cypress.config().
describe("Suite", { skipAfter: false }, () => {
it("test", () => {
//your code
});
after(() => {
if (Cypress.config().skipAfter) {
return;
}
//your code
});
});

How to delete data using Vue js?

I'm trying delete data but I'm getting this error:
this.jobPosts.filter is not a function
PostJobIndex.vue file:
deleteJobPost: async function(jobPost) {
if (!window.confirm('Are you sure you want to delete this Job Post?')) {
return;
}
try {
await employerService.deleteJobPost(jobPost.id);
this.jobPosts = this.jobPosts.filter(obj => {
return obj.id != jobPost.id;
});
console.log(this.jobPosts);
this.$toast.success("Job Post deleted Successfully!");
} catch (error) {
console.log(error);
this.$toast.error(error.response.data.message);
}
},
I had this same issue with my Update method and I beleive it was because I was trying to map through an object or something instead of an array. In the end I used Object.keys(this.jobPosts).map for my update method and it worked:
Object.keys(this.jobPosts).map(jobPost => {
if (jobPost.id == response.data.id) {
for (let key in response.data) {
jobPost[key] = response.data[key];
}
}
});
But when I do this for Update it doesn't work:
this.jobPosts = Object.keys(this.jobPosts).filter(obj => {
return obj.id != jobPost.id;
});
UPDATED
Here is the code for loading the job posts:
loadJobPosts: async function() {
try {
const response = await employerService.loadJobPosts();
this.jobPosts = response.data;
console.log(this.jobPosts);
} catch (error) {
this.$toast.error('Some error occurred, please refresh!');
}
},
Im using Vuex for state management and I'm using services, that simply contain the axios http requests. That's where this line comes from employerService.loadJobPosts() loadJobPosts() is a function inside my employerService.js file.
I'm also using Laravel for my back end. Here is my JobPostsController.php file:
public function index()
{
$jobPosts = JobPost::all()->where('user_id', Auth::user()->id);
return response()->json($jobPosts, 200);
}
From what I've understood from your code,
this should work for removing jobPost from jobPosts
this.jobPosts = this.jobPosts.filter(obj => {
return obj.id != jobPost.id;
});
I don't know what you're expecting this to do, but it won't do anything useful and will either error or return false for everything.
this.jobPosts = Object.keys(this.jobPosts).filter(obj => {
return obj.id != jobPost.id;
});
filter exists on array types, so I would check where it's getting set and make sure it's an array.
I've included a small snippet in case it's any help.
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: "#app",
data: () => {
return {
jobPosts: [],
deleteJobId: 1
};
},
methods: {
getJobPosts() {
this.jobPosts = [{
id: 1
}, {
id: 2
}, {
id: 3
}, {
id: 4
}, {
id: 5
}];
},
deleteJob() {
if (!this.deleteJobId)
return;
this.jobPosts = this.jobPosts.filter(x => x.id !== this.deleteJobId);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button type="button" #click="getJobPosts">Get Jobs</button>
<div>
<button type="button" #click="deleteJob">Delete Job #</button>
<input type="number" v-model.number="deleteJobId" />
</div>
<ul>
<li v-for="jobPost in jobPosts">
Job Post #{{jobPost.id}}
</li>
</ul>
</div>
You have already answered your own question:
in my data() object, I have this jobPosts: [], but in the console it says Object
As for your second question:
I don't know how to return the data as an array
There are similiar topics here on SO.
I am not familiar with Laravel but assuming you have an eloquent model with JobPost in your index-function according to the docs you should use the .toArray-method:
$jobPosts = JobPost::all()->where('user_id', Auth::user()->id).toArray();
When working with plain collections the values method should do the trick of returning an array instead of an object:
$collection = collect([
10 => ['product' => 'Desk', 'price' => 200],
11 => ['product' => 'Desk', 'price' => 200]
]);
$values = $collection->values();
$values->all();
UPDATE
I just realized that your result is just a stringified JSON object that needs to be converted into an array. Just parse it before processing (take out the JSON.parse(...) if you are already taking care of it in your service), return the object properties as an array and you are good to go:)
this.jobPosts = Object.values(JSON.parse(this.jobPosts)).filter(obj => {
return obj.id != jobPost.id;
});

Add array data to in vue without loosing old data

i am making vue application i want to add more data which is fetching through laravel return in array without loosing old data
my methods is
getData () {
axios.get('get/users')
.then(response => {
this.queue = response.data.users
})
.catch(e => {
this.errors.push(e)
})
}
and my data
data: function () {
return {
queue: []
}
},
Full Script is
data: function () {
return {
queue: []
}
},
created () {
this.getData()
},
methods: {
getData () {
axios.get('get/users')
.then(response => {
this.queue = response.data.users
})
.catch(e => {
this.errors.push(e)
})
},
decide (choice) {
this.$refs.tinder.decide(choice)
},
submit (choice) {
switch (choice) {
case 'nope': // 左滑
break;
case 'like': // 右滑
break;
case 'super': // 上滑
break;
}
if (this.queue.length < 2) {
this.getData()
}
}
}
here is video link
https://youtu.be/iv82EGMD4XA
i want when queue have 2 data left trigger this.getData()
fetch users and add array data to queue without loosing old queue data
You can use the concat function
this.queue = this.queue.concat(response.data.users);
In the axios response
Instead of the
this.queue = response.data.users

I need changed values on handclick from the Edit Form using custom action. How can I get it?

In the code below I want to get the form values from Edit form and sent using fetch on handleClick.
class GenerateButton extends Component {
handleClick = () => {
const { push, record, showNotification, values } = this.props;
const updatedRecord = { ...record, is_approved: true };
fetch(`api/reports/${record.id}`, { method: 'GET', body: updatedRecord })
.then((response) => {
return response.blob();
}).then(function(blob) {
console.log(blob);
})
.catch((e) => {
showNotification('Error: report generation failed.', 'warning')
});
}
render() {
return <RaisedButton label="Generate" onClick={this.handleClick} />;
}
}

How can I return an array of Promises from a then clause

I saw a similar question here which doesnt solve my problem. I am trying to run a cron job every 10 hours that lets me get the categories first and then based on the categories, i find the information for each category. How can I simplify the below Promise. I am NOT using Bluebird or Q, this is the native JS promise. Honestly, the code below looks like the same callback hell Promises were supposed to avoid, any suggestions
flipkart.getAllOffers = function () {
interval(43200, () => {
flipkart.findAllCategories()
.then((categories) => {
flipkart.save('flipkart_categories.json', categories)
if (categories) {
for (let item of categories) {
flipkart.findAllForCategory(item.category, item.top)
.then((items) => {
flipkart.save('flipkart_top_' + item.category + '.json', items)
}).catch((error) => {
console.log(error)
})
}
}
})
.catch((error) => {
console.log(error)
})
})
}
function interval(seconds, callback) {
callback();
return setInterval(callback, seconds * 1000);
}
If you stop using an extra level of indent just for .then(), then you have a pretty simple structure.
One .then() handler that contains
an if() statement
that contains a for loop
that contains another async operation
In this modified version, half your indent comes from your if and for which has nothing to do with promises. The rest seems very logical to me and doesn't at all look like callback hell. It's what is required to implement the logic you show.
flipkart.getAllOffers = function () {
interval(43200, () => {
flipkart.findAllCategories().then((categories) => {
flipkart.save('flipkart_categories.json', categories)
if (categories) {
for (let item of categories) {
flipkart.findAllForCategory(item.category, item.top).then((items) => {
flipkart.save('flipkart_top_' + item.category + '.json', items)
}).catch((error) => {
console.log(error)
throw error; // don't eat error, rethrow it after logging
});
}
}
}).catch((error) => {
console.log(error)
})
})
}
If flipkart.save() is also async and returns a promise, then you probably want to hook those into the promise chain too.
You can always create a helper function that may improve the look also like this:
flipkart.getAllOffers = function () {
interval(43200, () => {
flipkart.findAllCategories().then(iterateCategories).catch((error) => {
console.log(error);
})
})
}
function iterateCategories(categories) {
flipkart.save('flipkart_categories.json', categories);
if (categories) {
for (let item of categories) {
flipkart.findAllForCategory(item.category, item.top).then((items) => {
flipkart.save('flipkart_top_' + item.category + '.json', items);
}).catch((error) => {
console.log(error);
});
}
}
}
If you're trying to collect all the results (something your title implies, but your question doesn't actually mention), then you can do this:
flipkart.getAllOffers = function () {
interval(43200, () => {
flipkart.findAllCategories().then(iterateCategories).then((results) => {
// all results here
}).catch((error) => {
console.log(error);
});
})
}
function iterateCategories(categories) {
flipkart.save('flipkart_categories.json', categories);
let promises = [];
if (categories) {
for (let item of categories) {
let p = flipkart.findAllForCategory(item.category, item.top).then((items) => {
flipkart.save('flipkart_top_' + item.category + '.json', items);
}).catch((error) => {
console.log(error);
});
promises.push(p);
}
}
// return promise here that collects all the other promises
return Promise.all(promises);
}

Resources