i'm trying to update url without params is it possible ? on my app i created state
.state('webPrint', {
url: '/web/print/:lead',
templateUrl: '/application/views/web-print.html'
})
and when i'm redirecting i'm passing an object
var obj = JSON.stringify(lead);
$state.go('webPrint', { lead: obj });
but my url is something should be like
/web to /web/print but it shows /web/print + "stringify object data" so i changed my code to
$state.go('webPrint', { lead: obj }, { location: false, inherit: false });
but now it's not change url at all. i mean /web to /web
how can i avoid stringify string on url and pass direct to new url?
thanks
You are using option location: false which means you are telling not to change the url.
I would say create a service with getter and setter to save and retrieve your data like below
angular.module('app.service').factory('leadService', function(){
var lead = {};
return{
getLead : function(){
return lead;
},
setLead: function(data){
lead = data;
}
}
});
.state('webPrint', {
url: '/web/print',
templateUrl: '/application/views/web-print.html'
})
var obj = JSON.stringify(lead);
leadService.setLead(obj);
$state.go('webPrint');
Then in your controller get the lead Object using
var lead = leadService.getLead();
Related
This is my app state
.state('app', {
url: "/?:site_id",
templateUrl: "/controls/angular/templates/partial/app.html",
abstract: true
})
.state('app.popup', {
url: "popup",
templateUrl: "/controls/angular/templates/popup.html",
controller: 'PopupController'
})
The app root (that config as abstract) has parameter (site_id) that I can use in all other pages in the application.
I have drop-down list that can change the site.
How can I add the site url parameter to current page with all other parameters that exist
Just change the root site_id parameter.
var oSelect = $('#site_select_tag').select2();
oSelect.on("change", function (e) {
var curr_site_id = e.val;
$state.go to => ?????????
//scope.site_id = e.val;
scope.onChange()(e.val);
});
Thanks
The solution is simple
$state.go('.', {site_id: e.val})
Keep all other parameters and set the new parameter
You can pass options to the go method of $state:
$state.go(to [, toParams] [, options])
https://github.com/angular-ui/ui-router/wiki/Quick-Reference#stategoto--toparams--options
$state.go('myState', {'myParam': myValue});
And you can set parameters on ui-sref:
ui-sref='stateName({param: value, param: value})'
https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref
<a ui-sref="myState({'myParam': myValue})">myLink</a>
You can access the current state as $state.current.name and the current parameters as $state.params so what you can do is this:
var params = $state.params;
params.id = 123; // Set new ID
$state.go($state.current.name, params);
If I understand you correctly your trying to manipulate the state data after it is set up in the $stateProvider. If so you should set up your own state provider like Mean.io do
// $meanStateProvider, provider to wire up $viewPathProvider to $stateProvider
angular.module('mean.system').provider('$meanState', ['$stateProvider', '$viewPathProvider', function($stateProvider,viewPathProvider){
function MeanStateProvider() {
this.state = function(stateName, data) {
if (data.templateUrl) {
data.templateUrl = $viewPathProvider.path(data.templateUrl);
}
$stateProvider.state(stateName, data);
return this;
};
this.$get = function() {
return this;
};
}
return new MeanStateProvider();
}]);
How to use $state.go() if I have just the URL ?
Or can I get a state based on URL? (and than use $state.go(state))
I'm asking because I had to intercept the $urlRouterProvider.otherwise() to wait for an other plugin loads some external modules.. and now I need to continue and call the URL that call otherwise()
In place of $state.go(), you can use $location service as well.
i.e.
$location.path(url)
Please take care of not using # in URL. You can also use window.location.href
I had a similar problem, and $location wasn't helping, so I wrote a function to get the state from the url.
NB: I am using nested states based on ui-router.stateHelper, so I traverse my nested states object, testing for url matches. It would be slightly different when using dot notation to define nested states - and even easier if you don't use nested states at all!
function goPath (path) {
var target;
var arr = path.match(/\/\w+/g);
var i = 0;
var testState = function (state, i) {
if (state.url === arr[i]) {
target = state;
if (state.children && state.children.length && arr.length > i+1) {
i++;
state.children.forEach( function (childState) {
testState(childState, i);
});
}
}
};
myStatesObj.forEach( function (state) {
testState(state, i);
});
$state.go(target.name);
};
I was on a similar situation, what I did is changed the location to a different path and reset it to the current after a timeout like this
var path = $location.path();
$location.path("/");
$timeout(function(){
$location.path(path).replace(); //use .replace() so the empty path won't go to the history
},0);
i'm adding a full answer to this due to the high number of views.
NOTE: location.search() is only used where you need to handle a URL with a query string in it. otherwise use location.path() only.
your ui.router login state should look something like ...
.state('login', {
url: '/login',
templateUrl: 'routes/login/login.html',
controller: 'LoginController',
controllerAs: 'loginCtrl',
authenticate: false,
params: {
fwdPath: undefined, // Location to forward to on login success
fwdQueryStringObject: undefined // Query string object to use on login success - retrieved from $location.search()
}
})
your 401 (unauthorised) interceptor should look something like ...
state.go('login', {fwdPath: location.path(), fwdQueryStringObject: location.search()});
your login controllers login function should call your login service's login function. the code INSIDE the controllers login function should look something like ...
loginService.login(self.username, self.password).then(function (response) {
// local vars prevent unit test failure
var fwdPath = state.params.fwdPath;
var fwdQueryStringObject = state.params.fwdQueryStringObject;
if (response.status === 200) {
timeout(function () {
if (fwdPath != null) {
location.path(fwdPath).search(fwdQueryStringObject);
location.replace();
} else {
state.go('home');
}
}, 400);
} else {
self.error = true;
}
self.pending = false;
}
};
and finally your unit tests ...
state.params.fwdPath = '/login/list';
state.params.fwdQueryStringObject = {q: 5};
spyOn(location, 'path').and.callThrough();
spyOn(location, 'search').and.callThrough();
...
expect(location.path).toHaveBeenCalledWith('/login/list');
expect(location.search).toHaveBeenCalledWith({q: 5});
I want $http.get method to work when a form is submitted.
Here is my code. The object $scope.questions is being set when the method is called but the data doesn't show up in the div. Moreover, when the $http.get method is outside the signIn() function it works just fine.
$scope.signIn = function(data) {
$location.path('/profile');
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(questionData) {
$scope.questions = questionData;
console.log($scope.questions);
});
};
<div>
User Profile
<br/>Question Posted
<br/>
<input ng-model="query.title" id="value" type="text" placeholder="Search by Title..." ">
<div>
<ul>
<li ng-repeat="question in questions | filter: query ">
{{question.title}}
</li>
</ul>
</div>
<br/>
</div>
You need to move your $location.path('/profile') inside your http request. Remember that a http request is async call. You should redirect after getting the data not before.
$scope.signIn = function(data) {
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(questionData) {
$scope.questions = questionData;
console.log($scope.questions);
$location.path('/profile');
});
};
If you're redirecting to another route with a completely separate scope you will lose any scope you're setting in the success handling.
From what I'm reading you're clicking a button to do an action. After that action you're redirecting to another page with a separate controller and trying to persist the data.
Unfortunately, Angular hasn't figured out a great way to do this. The easiest way to persist data through controllers and scope is to create a service that will store it in one controller and grab it in another controller.
For instance:
$scope.signIn = function(data) {
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(questionData) {
$location.path('/profile');
storageService.store("question", questiondata)
});
};
Your new factory to persist data through:
angular.module('moduleName').factory('storageService', [
function () {
return {
store: function (key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
get: function(key) {
return JSON.parse(localStorage.getItem(key));
},
remove: function(key) {
localStorage.removeItem(key);
}
}
}
]);
Other controller to access data:
$scope.question = storageService.get("question");
// remove localstorage after you've grabbed it in the new controller
storageService.remove("question");
An alternative to doing the somewhat 'hacky' way of using localStorage to persist data through controllers is to use ui-router and have a resolve on the route you're redirecting to.
For instance:
$scope.signIn = function(data) {
$state.go('profile');
};
In your route file:
.state('profile', {
url: '/profile'
controller: profileControllerName,
templateUrl: 'profileHtmlTemplate.html',
resolve: {
'questions': [function() {
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(res) {
return res.data;
});
}]
}
}
In your profile controller:
Inject your 'questions' resolve into your controller and assign `$scope.question = questions;
This will make the HTTP call as soon as you click the route, return the data if successful, then render the page. It will NOT render the page if the resolve does not return success. This will ensure your data will be loaded before you load the page that depends on that data.
I would highly recommend using services to hold your HTTP calls for specific parts of your application. If you have a GET questions, POST question, PUT question. I would create a questionService and make all my HTTP methods there so you don't have to clutter your routes. You would only have to call:
.state('profile', {
url: '/profile'
controller: profileControllerName,
templateUrl: 'profileHtmlTemplate.html',
resolve: {
'questions': [function() {
return questionService.getQuestions(id).then(function(res) {
return res.data;
})
}]
}
}
I have the following angular code:
application.controller('ImageController', function ImageController($scope, ImageService, ngDialog) {
$scope.open = function (image) {
ngDialog.open({
className: 'modal',
plain: false,
scope: scope,
template: 'image'
});
}
};
On page loading, when the url has the parameters source and key:
http://www.google.pt/?source=1&key=sdfd-sd-sf
I would like to call open and pass an image with:
image.source = 1;
image.key = sdfd-sd-sf;
How can I do this?
UPDATE
I tried to use ngroute:
$routeProvider
.when('/:source?/:key?',
{
controller: "ImageController"
}
)
with the following route:
domain.com/?source=ddf&key=23jf-34j
On ImageController I tried to get the parameters source and key using:
var image = { source: $routeParams.source, key: $routeParams.key };
if (image.source != null && image.key != null) {
open(image);
}
But both source and key are undefined. Any idea why?
If you're using ngRoute, you can inject $routeParams into your controller and simply do:
image.source = $routeParams.source;
image.key = $routeParams.key;
Nice egghead video about it: https://thinkster.io/egghead/routeparams-api/
UPDATE
There's no need to specify query parameter names in when (it's only needed when using paths like domain.com/source/123/key/456), so this is wrong:
.when('/:source?/:key?',
It should be just:
.when('/',
While your URL has the hashbang (or html5mode):
domain.com/#/?source=ddf&key=23jf-34j
then this will work just fine:
var image = { source: $routeParams.source, key: $routeParams.key };
Note that if you're not using ng-view the parameters won't be available due to their async nature, so you need to use this watcher in your controller:
$scope.$on('$routeChangeSuccess', function() {
console.log($routeParams);
});
or, if you inject $route instead of $routeParams, you can use:
$scope.$on('$routeChangeSuccess', function() {
console.log($route.current.params);
});
it will return the same object.
UPDATE 2
After a little research, seems like by far the easiest way to do it is to inject $location service, and simply use:
var params = $location.search();
var image = { source: params.source, key: params.key };
Here is a simple example with html5 mode on (will work with your original URL): http://run.plnkr.co/sElZhTrI4JvGc0if/?source=SomeSrc&key=SomeKey
And the full Plunker: http://plnkr.co/edit/Jxol8e7YaghbNScICHqW
I am trying to send the current tab url to the resource service { in param } .
but the global tablUrl is not having any value at
var url = "http://[localhost]/getProfile?domain="+tabUrl
but getting logged corrent at :
console.log(tabUrl);
this is my code :
var tabUrl;
angular.module('jsonService', ['ngResource'])
.factory('JsonService', function($resource) {
chrome.tabs.getSelected(null, function(tab) {
tabUrl = tab.url;
console.log(tabUrl);
});
var url = "http://[localhost]/getProfile?domain="+tabUrl
return $resource(url,{}, {
list : {
method : 'GET',
cache : true
}
});
});
template binding :
<body ng-controller="extensionCtrl">
this is controller :
app.controller('extensionCtrl', function($scope , JsonService) {
JsonService.get(function(data){
$scope.data = data;
});
});
First:
Please, don't use the deprecated chrome.tabs.getSelected. Use chrome.tabs.query instead.
Second:
chrome.tabs.getSelected/chrome.tabs.query are asynchronous. This means that execution continues while they do some work in the background and the specified callback is called when they are done.
So, in a case like this:
line 1: chrome.tabs.getSelected(null, funkyCallback);
line 2: var url = ...
line 3: return $resource(...);
...a possible (and very probable) order of execution is:
1. chrome.tabs.getSelected (starts retrieving the active tab in the background)
2. line 2 gets executed (at this time 'tabURL' is not set yet)
3. line 3 gets executed (returning something)
4. Once the the active tab is retrieved, 'funkyCallback' is called
(setting 'tabURL' after it is too late).
When using asynchronous APIs (such as most of the chrome.* APIs), you have to change the whole logic of your scripts to be in line with the asynchronous nature of the API calls.
E.g., you could achieve the same result like this:
HTML:
<html ng-app="jsonService">
...
<body ng-controller="extensionCtrl">
<p>{{jsonData}}</p>
...
JS:
var app = angular.module("jsonService", ["ngResource"]);
app.factory("JsonFactory", function($resource) {
var url = "http://localhost/getProfile?domain=:tabUrl";
var retObj = $resource(url, {}, {
list: {
method: "GET",
cache: true
}
});
return retObj;
});
app.controller("extensionCtrl", function($q, $rootScope, JsonFactory) {
chrome.tabs.query({ active: true }, function(tabs) {
JsonFactory.list({ tabUrl: tabs[0].url }, function(data) {
// On success...
$rootScope.jsonData = data;
}, function(data) {
// On error...
$rootScope.jsonData = "Error using JsonFactory.list(...) !";
});
});
});
See, also, this short demo that does something similarly asynchronous