angularjs $resource update using PUT fails when parameter name changes - angularjs

I'm missing something in my understanding or code here...
I've got a very basic CRUD app to list/add/edit/delete categories, and it works fine when I define the primary key on the table as "id", but when I rename the database column to "categoryId", the PUT url does not include the key value, and I end up for a 404 error for an unhandled path...
stack:
IIS 7.5 w/ Slim PHP for RESTful services
// Route excerpt
...
when('/categories', {templateUrl: 'partials/categoryList.html', controller: CategoryListCtrl}).
when('/categories/new', {templateUrl: 'partials/categoryDetail.html', controller: CategoryNewCtrl}).
when('/categories/:id', {templateUrl: 'partials/categoryDetail.html', controller: CategoryEditCtrl}).
...
angular.module('myServices', ['ngResource'])
.factory('Category', function($resource){
return $resource('../api/index.php/categories/:id', {id:'#categoryId'},
{ update: {method:'PUT' } }
);
})
// WORKS when attribute is 'id'
.factory('Category', function($resource){
return $resource('../api/index.php/categories/:id', {id:'#id'},
{ update: {method:'PUT' } }
);
})
// FAILS with 404 when attribute is 'categoryId'
.factory('Category', function($resource){
return $resource('../api/index.php/categories/:id', {id:'#categoryId'},
{ update: {method:'PUT' } }
);
})
Of course there are a number of other places in the code where the name is changed, but the effect I'm seeing seems to be related to the ngResource.
The first method produces an URL that works...
categories/1?description=null&name=Observation&report=null
/api/index.php
The second produces this...
categories?categoryId=1&description=null&name=Observation&report=null
/api/index.php
with the 404 error due to the malformed path.
Is there another parameter (or directive or something) required to get the renamed attribute to be used in the URL?

I tested the put with the second resource and it works as expected. The only way I could reproduce that was if I was issuing a GET instead of a PUT. If you open this demo and view the network tab (chrome/etc) you can see what the put and what the get produce.
http://plnkr.co/edit/tI9KpqDp49pXuJJVjivm?p=preview
The GET produces the querystring parameterized data:
GET produces:
Request URL:http://run.plnkr.co/api/index.php/categories?categoryId=123
Request Method:GET
PUT produces:
Request URL:http://run.plnkr.co/api/index.php/categories/123
Request Method:PUT
Code:
var test= $resource('../api/index.php/categories/:id', {id:'#categoryId'},
{ update: {method:'PUT' } }
);
var test2= $resource('../api/index.php/categories/:id', {id:'#categoryId'},
{ get: {method:'GET' } }
);
test.update({categoryId:123});
test2.get({categoryId:123});

Related

404 page in angular ui-router

I am using ui-router in an angular single page application. I have some routes defined, and I have a specific 404 route like this:
app.config(function($urlRouterProvider, $stateProvider){
$urlProvider.otherwise('404')
$stateProvider
.state('example', {
url: '/example/:id',
templateUrl: 'example.html',
controller: 'ExampleController'
})
.state('404', {
url: '*path',
templateUrl: '404.html'
})
})
Notice how the url for 404 state is '*path', which means it will match any path. I made it so if the user types something like '/some-non-existent-url' he won't be redirected to '/404', but rather stay at '/some-non-existent-url', but see the 404.html template. Here comes the problem: say my app interacts with some REST API inside my ExampleController, and the API may return an object, or it may return 404 Not Found based on the id from the url it receives. So, inside my controller, whenever this happens, I try to redirect to 404:
app.controller('ExampleController', function($state){
someAPICall().then(function(response){ // do something},
function(response){
if(response.status == 404){
$state.go('404');
}
});
});
This is where the weird staff occurs. It displays the 404.html template - for a split second - and then redirects to home page (did not include it in my code here for the sake of brevity). My guess is that the '404' state does not have a real url specified: if I change it's url from '*path' to '/404' for example, this works fine, but I don't want to do this, as the user won't see which was the real url that caused a 404 response. Is there any workaround for this problem?
You have a mistake in your code. You are writing $urlProvider.otherwise('404'). Change it to $urlRouterProvider.otherwise('404').
That should get it working.
What worked for me was to remove $urlProvider.otherwise('404') and have the 404 state as the last state

Dynamic route request render not working, backend express

I want to try dynamic route request but It's not working properly. And here I explain my coding style step by step.
<nav class="main-nav" ng-show="global.user.user_type!='admin'" ng-repeat="mMenu in Mainmenu">
{{mMenu.MenuName}}
</nav>
This code contain URL link and It's load every time with a variable that is web address link. And the link is something like that - http://localhost/views/adminpanel/about.html
In AngularJS Controller contain the code -
$scope.geturl = function(url)
{
var params = {
url1 : '/views/adminpanel/'+url
}
$http({'method' : 'post', url : 'views/adminpanel/'+url, data: params
}).success(function(data)
{
}).
error(function(data){
})
}
configuring and using ngRoute -
when('/views/adminpanel/:url', {
controller: 'homeCntrl',
templateUrl: 'views/adminpanel/:url'
})
In server side (Express) :
Routing HTTP requests, Configuring middleware and Rendering HTML views
app.post('/views/adminpanel/:url',auth.requiresLogin, users.geturl);
exports.geturl= function(req,res)
{
var url = req.body.url1;
res.render(url);
}
This is all about my rendering process but It's not working. In browser It only shows the URL link but not shows any content. How can I solve It any idea?
I think you are confusing things:
first of all you have a link together with a ngClick: you should have either of those
your ngClick has an empty success function, so it does nothing with the template
you have a route set with express that matches with the ngRoute (btw, POST is usually used to create resources, you should GET the template)
your templateUrl is going to send a GET request to (literally) /views/adminpanel/:url, it does not replace :url
To fix it:
set a different endpoint for your APIs
use a GET endpoint instead of a POST
change the ngRoute to:
when('/views/adminpanel/:url', {
controller: 'homeCntrl',
templateUrl: function(param) {
return '/api/<path>/' + param.url;
}
})
remove the ngClick from the <a>

send parameter along url angularjs

I am working on project where my role is server-side programmer.Client side developer used Angular js while designing pages.
Problem I am facing is we have one page where I need to pass one parameter along with url to server
<a id="startQuiz" href="#/Quiz" >Start Quiz</a>
jquery code is
$('#startQuiz').click(function (e) {
e.preventDefault();
window.location.href = '#/Quiz/' + selectedTopic;
}
Controller code is
#RequestMapping(value="/Quiz", method = RequestMethod.GET)
public String Quiz(HttpServletRequest request,Model model,HttpServletResponse response,#RequestParam(value = "topic", required = false) String topic) throws Exception {
System.out.println("select topic : "+topic);
}
I am getting topic as null cause Nothing after the hash # sign is getting sent to the server, hence the null values
Rounting file Is
app.config(function($routeProvider){
$routeProvider
.when("/Quiz", {templateUrl: "Quiz", controller: "PageCtrl"})
});
So, What change should I make in routing so I can get value of topic in Controller
Any way to do that?
The URL of the page is not what matters here. That URL will only load the main page template.
What matters is the URL used to send the AJAX request to your backend controller.
The route should be defined as
$routeProvider
.when("/Quiz/:topicId", {
templateUrl: "Quiz",
controller: "PageCtrl"
})
Then, using the $routeParams service in the PageCtrl, you can get the value of topicId, and send the appropriate AJAX request to the backend.

How to multilingual url when user enter, copy paste or click url from other website

I have angularjs project implemented multi-language and using ui-router for routing. Every language will be have different url. Ex:
http://example.com/!#/en-us/english-title
http://example.com/!#/es-es/spanish-title
All state with url registered automatically when app run and load them from database. Ex:
angular.module('bxApp').run(["$http", function ($http) {
$http.get('/Home/Routes').success(function (result) {
result = result || {};
if (angular.isDefined(result) && result !== null) {
_.each(result.Routes, function (route) {
stateProvider.state(route.Name, {
url: route.Url,
templateUrl: route.TemplateUrl,
controller: route.Controller,
});
});
}
});
}]);
It work well but it will not work when user copy this link and paste to browser or click this link from other website . I think because of state can't found so it will be redirect to default and it does not keep url that user enter or copy.
In this case , How to do that?
Thanks,
You're declaring your states as a result of an HTTP call to your server: the problem is that these states are defined too late for the user to navigate to them when he pastes the URL in a new tab.
To understand, let's deconstruct what happens :
The user is on the initial page / other website, and copies the URL.
He pastes it in a new tab
Your angular application loads, finishes its config phase without having declared any of those states, and sends an HTTP call.
ui-router fails to route to a state matching the pasted URL, since the corresponding state is not here yet, and redirects to default
The HTTP response comes back, and your states are created (but too late).
How to make it work ?
My first reaction would simply not to store your states on your server. Unless you want the very core of your UX to be language-dependent, you don't have to do that.
But hey, let's say we want to do it anyway. I suggest you try this : declare a toplevel 'language' state, and have it load the other states in a resolve clause. This will 'block' the routing until the other states are declared :
angular.module('bxApp')
.config(['$urlRouterProvider', function ($urlRouterProvider) {
$urlRouterProvider
.state('language',{
url: '/:language',
resolve: {
childrenLoaded: ['$http', function ($http) {
// returning a promise is essential to have the 'waiting' behavior
return $http.get('/Home/Routes').then(function (data) {
var result = data.result || {};
if (angular.isDefined(result) && result !== null) {
_.each(result.Routes, function (route) {
$stateProvider.state(route.Name, {
url: route.Url,
templateUrl: route.TemplateUrl,
controller: route.Controller
});
});
}
});
}]
}
})
}]);
Again, this approach is probably asking for trouble : I strongly recommend you hardcode your states instead of storing them in a database. If all that varies from one language to another is the text and URL, then you will be fine with an URL param.

How to inject resolved data into controller?

I can see the RESTful service being called within loadProfile before this route is accessed....
$routeProvider.when('/editProfile', {
templateUrl: '/views/user/editprofile',
controller: 'UserCtrl',
access: access.user,
resolve: {
userProfile: function(UserSvc){
UserSvc.loadProfile(function(userProfile){ return userProfile });
}
}
});
So how do I then get that data injected into my User controller?
UPDATE 1:
Matt Way clued me in on how to get the resolved data injected in my controller. However, I immediately got an error "Unknown Provider: userProfileProvider". Based on some other similar questions, I decided to try to remove the ng-controller="UserCtrl" attribute from the view in question. The Unknown Provider error disappeared for my /editProfile route, but then started to appear on all of the other views/routes for this controller.
UPDATE 2
I watched a couple videos on egghead.io and found I was able to access the promised data in the $route. Added this to my controller and voila!
if($route.current.locals.userProfile){
$scope.userProfile = $route.current.locals.userProfile;
}
Simply include the resolve items name as an input to your controller function. Eg:
myApp.controller('UserCtrl', ['$scope', 'userProfile',
function($scope, userProfile) {
// Controller code goes here
}]);
Can you return the loaded profile? I think that's why you're getting the unknown provider error.
function (UserSvc) {
return UserSvc.loadProfile(function(userProfile) { return userProfile });
}
As a side note, I saw your comment where you pasted your controller function and it looks like there are a lot of dependencies. Might be better to reduce the number of collaborators needed.

Resources