Here is my simple angular 1 app.
Source code here.
Basically it is a copy of this.
I am able to do CRUD operations. The issue is that, when I delete a record. It redirects back to the home page. The record I deleted is still here. If I refresh the page, it is gone.
Is it a way to delete a record and then after redirect, I should see the latest list?
Update 1:
Unfortunately, it is still unresolved. Something strange that it seems the promise in resolve is cached. I added a few console.log inside the code. You can see the code flow. Open chrome developer tool to see it.
i review you code , the problem is here:
this.deleteContact = function(contactId) {
var url = backend_server + "/contacts/" + contactId;
// actually http delete
return $http.delete(url)
.then(function(response) {
return response;
}, function(response) {
alert("Error deleting this contact.");
console.log(response);
});
}
if you have service to manage your contact use there to call your server to delete the contact.
the reason you cannot delete without refresh is:
your delete from DB but not from angular array.
must review (update the scope (array))
your code is hard to read , i have suggestion for you, using:
broserfy , watchify
lodash
and backen use mvc
You delete it remotely but not locally. So you can see result only after refreshing (only after you requesting updated data from server). You need to update your local contacts after you succeed on server side.
$scope.deleteContact = function(contactId) {
Contacts.deleteContact(contactId).then(function(data){
...
//DELETE YOU LOCAL CONTACT HERE
...
$location.path("/");
});
}
I didn't look deeply into your code, so I can't say how exactly you should do it, but as I see you keep your local contacts in $scope.contacts in your ListController.
Related
I have a problem with a meteor publication not being reactive when using a query inside it.
Let's say I have many files, and each file has many projects, so I can go to the route:
http://localhost:3000/file/:file_id/projects
And I would like to both display the projects of the selected file and add new projects to it.
I am currently using angularjs, so the controller would look something like this:
class ProjectsCtrl {
//some setup
constructor($scope, $reactive, $stateParams){
'ngInject'
$reactive(this).attach($scope)
let ctrl = this
//retrieve current file id
ctrl.file_id = Number($stateParams.file)
//get info from DB and save it in a property of the controller
ctrl.subscribe('projects', function(){return [ctrl.file_id]}, function(){
ctrl.projects = Projects.find({file_id: ctrl.file_id}).fetch()
})
//function to add a new project
ctrl.addProject = function(){
if(ctrl.projectName){
Meteor.call('projects.insert', {name: ctrl.projectName, file_id: ctrl.file_id }, function(error, result){
if(error){
console.log(error)
}else{
console.log(result)
}
})
}
}
}
}
The publication looks something like this:
Meteor.publish('projects', function(file_id){
return Projects.find({file_id: file_id})
})
The problem is that, if I insert a new project to the DB the subscription doesn't run again, I mean the array stays the same instead of displaying the new projects I am adding.
I got many problems with this as I thought that meteor would work something like: "Oh there is a new project, let's re run the query and see if the publication change, if it does, let's return the new matching documents"... but no.
I have not found a problem similar to mine as every question regardind querys inside the publication is about how to reactively change the query (the file_id in this case) but that is not the problem here as I don't change the file_id unless I go to another route, and that triggers a new subscription.
My current solution is to expose the complete collection of projects and make the query using minimongo, but I don't know if it is a good workaround (many projects exposed uses too much memory of the browser, minimongo is not as fast as mongo... etc, I don't really know).
Your issue is that the Meteor.subscribe call doesn't know that file_id has changed. There's no reactive relationship between that argument and executing the subscription.
To fix this, whenever you are passing criteria in publish-subscribe, you must write a subscription of Collection inside a tracker.
To know more about trackers, Click here.
While I'm unsure how to do this in Angular, consider this simple Blaze template as an example:
Template.Name.onCreated(function(){
this.autorun(() => {
Meteor.subscribe('projects', file_id);
});
});
Whenever file_id changes, a new subscription is triggered, giving you the desired effect of auto pub-sub utility.
I hope this will give you some insight. It could be easily achieved via Angular JS as well.
I have been looking around for suitable ways to 'clean up' created records after tests are run using Protractor.
As an example, I have a test suite that currently runs tests on create and update screens, but there is currently no delete feature, however there is a delete end point I can hit against the backend API.
So the approach I have taken is to record the id of the created record so that in an afterAll I can then issue a request to perform a delete operation on the record.
For example:
beforeAll(function() {
loginView.login();
page.customerNav.click();
page.customerAddBtn.click();
page.createCustomer();
});
afterAll(function() {
helper.buildRequestOptions('DELETE', 'customers/'+createdCustomerId).then(function(options){
request(options, function(err, response){
if(response.statusCode === 200) {
console.log('Successfully deleted customer ID: '+ createdCustomerId);
loginView.logout();
} else {
console.log('A problem occurred when attempting to delete customer ID: '+ createdCustomerId);
console.log('status code - ' + response.statusCode);
console.log(err);
}
});
});
});
//it statements below...
Whilst this works, I am unsure whether this is a good or bad approach, and if the latter, what are the alternatives.
I'm doing this in order to prevent a whole load of dummy test records being added over time. I know you could just clear down the database between test runs, e.g. through a script or similar on say a CI server, but it's not something I\we have looked into further. Plus this approach seems on the face of it simpler, but again I am unsure about the practicalities of such an approach directly inside the test spec files.
Can anyone out there provide further comments\solutions?
Thanks
Well, for what it's worth I basically use that exact same approach. We have an endpoint that can reset data for a specific user based on ID, and I hit that in a beforeAll() block as well to reset the data to an expected state before every run (I could have done it afterAll as well, but sometimes people mess with the test accounts so I do beforeAll). So I simply grab the users ID and send the http request.
I can't really speak to the practicality of it, as it was simply a task that I accomplished and it worked perfectly for me so I saw no need for an alternative. Just wanted to let you know you are not alone in that approach :)
I'm curious if other people have alternative solutions.
The more robust solution is to mock your server with $httpBackend so you don't have to do actual calls to your API.
You can then configure server responses from your e2e test specs.
here's a fake server example :
angular.module('myModule')
.config(function($provide,$logProvider) {
$logProvider.debugEnabled(true);
})
.run(function($httpBackend,$log) {
var request = new RegExp('\/api\/route\\?some_query_param=([^&]*)');
$httpBackend.whenGET(request).respond(function(method, url, data) {
$log.debug(url);
// see http://stackoverflow.com/questions/24542465/angularjs-how-uri-components-are-encoded/29728653#29728653
function decode_param(param) {
return decodeURIComponent(param.
replace('#', '%40').
replace(':', '%3A').
replace('$', '%24').
replace(',', '%2C').
replace(';', '%3B').
replace('+', '%20'));
}
var params = url.match(request);
var some_query_param = decodeURIComponent(params[1]);
return [200,
{
someResponse...
}, {}];
});
});
Then load this script in your test environnement and your done.
I have the following publisher and subscriber code.
It works for the first time when the app starts, but when I try to insert data directly into the Mongo database, it will not automatically update the user screen or I don't see the alert popping.
Am I missing something?
Publish
Meteor.publish('userConnections', function(){
if(!this.userId){
return;
}
return Connections.find({userId: this.userId});
})
Subscribe
$scope.$meteorSubscribe('userConnections').then(function () {
var userContacts = $scope.$meteorCollection(Connections);
alert("subscriber userConnections is called");
if (userContacts && userContacts[0]) {
....
}
}, false);
First off, if you are not using angular-meteor 1.3 you should be. The API has changed a lot. $meteorSubscribe has been deprecated!
To directly answer your question, $meteorSubscribe is a promise that gets resolved (only once) when the subscription is ready. So, it will only ever be called once. If you look at the documentation for subscribe you'll see how to make the binding "reactive", by assigning it to a scope variable. In your case it would be something like:
$scope.userContacts = $scope.$meteorCollection(Connections);
Doing it this way, when the collection gets updated, the $scope.userContacts should get updated as well.
I have an angular / breeze / webapi app which works great except if I refresh a page which has a EntityQuery to return one entity. It then complains that the metadata is not available as the entityquery does not trigger a metadata fetch, unlike a standard query.
If we have reached the page from a previous angular page which has fired a standard breeze query then the metadata is already there and we have no problem.
So question is, how do I check the metadata exists and trigger the metadata call if it is not already done?
Many thanks for any help you can give me.
Try something like this:
function fetchMetadata() {
var manager = new breeze.EntityManager("api/breeze");
if (manager.metadataStore.isEmpty()) {
return manager.fetchMetadata();
}
return Q.resolve();
}
function start() {
fetchMetadata().then(function () {
// Metadata fetched.
// Do something here.
});
}
I have isolated the problem down to a few lines. With IIS express it calls the PUT on the web API. When I switch to using IIS with the same code the call to the PUT method never happens.. The GET call works with both just fine.. any idea?
$scope.save = function (msa) {
$scope.msa = msa;
var id = this.msa.PlaceId;
Msa.update({ id: id }, $scope.msa, function () {
alert('finished update'); //only gets here with iis express
$scope.updatedItems.push(id);
$location.path('/');
});
}
MsaApp.factory('Msa', function ($resource) {
return $resource('/api/Place/:id', { id: '#id' }, { update: { method: 'PUT' } });
});
EDIT 1:
I thought it was working but now it only works when 'localhost' and not the computer name.. it is not calling the server method.. any ideas what things to look out for that make the site act differently from localhost to ? .. and even stranger.. the angular site wont load in IE.. but it loads in chrome
EDIT 2:
I think I have the answer.. The dewfault webapi PUT/UPDATE creates invalid code.. It sort of randomly would breaking at db.Entry(place).State = EntityState.Modified... I found code here that seems to fix it so far.. not exactly sure what it does though
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key
Remove WebDAV module from IIS, it should work
IIS does block some of the actions by default, I believe PUT is one (DELETE is another).
See: https://stackoverflow.com/a/12443578/1873485
Go to Handler Mappings in your IIS Manager. Find ExtensionlessUrlHandler-Integrated-4.0, double click it. Click Request Restrictions... button and on Verbs tab, add both DELETE and PUT.