$http.get method not working on ng-submit - angularjs

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;
})
}]
}
}

Related

Fetch data from database in angularjs to form

In front page there are two options:
1.create new
2.edit
1.it goes to index.html
2.it should be goes to index html with data(data should be load from database)
//get data from database
$scope.getItem = function(id) {
var auth = btoa("root:root");
$scope.form["#class"] = "ProjectDetails";
$http.defaults.headers.common.Authorization = 'Basic ' + auth;
$http.get("http://azuspeedcp01:2480/document/InternalRPA/"+id+"/*:-1", {
})
.then(function(response) {
console.log(response);
$scope.form=response.data;
});
}
here i retrieve data from db is fine.its response.data
again assign to $scope.form which is the object i passed from form to submit data.
//index.html(partial)
<input type="text" id="clientName" ng-model="form.ClientName">
<input type="text" id="initiate" ng-model="form.City">
<select id="Geo" ng-model="form.Geo">
<option value="North America">North America</option>
</select>
How to route to index.html with data. I don't have idea.please help me.
it goes to index.html
it should be goes to index html with data(data should be load from database)
So you want always staying in the same screen, then why you want to redirect(refresh) on the same screen? You can use the same scope object anywhere in the same screen(index.html),
it should be goes to index html with data(data should be load from database)
If you want to redirect with data. then Just use location.$path("routename") to redirect the screen and maintain the values by using $localStorage
I found the answer that I can use angular service to route from one service to another.Thanks all to help me
app.service('srvShareData', function($window) {
var KEY = 'App.SelectedValue';
var addData = function(newObj) {
alert("2"+newObj);
$window.sessionStorage.setItem(KEY,JSON.stringify(newObj));
};
var getData = function(){
var mydata = $window.sessionStorage.getItem(KEY);
return mydata;
};
return {
addData: addData,
getData: getData
};
})

Howto submit a form with Angular and displaying results on a different page

I'm trying to submit a form from a HTML page using angular.
My HTML code is:
<form role="search">
<input type="text" ng-model="searchSring">
<button type="submit" ng-click="searchPerson(searchString);">Get it!
</button>
</form>
The searchPerson function is calling some PHP page using Ajax and data is successfully retrieved from it.
What I want is when the user has clicked the Get it! button, he should be routed to another HTML page where I would like to display the results. I've tried using "action=" in the form and even calling window.location once Ajax completed to route to the next page. Every time the result is cleared. I've tried using factory with get/set, but this too clears the data on the second page after the window.location call.
Here's the factory code:
myApp.factory('searchService', function(){
var searchService = {};
var mySearchResult = {};
searchService.set = function(searchResult){
mySearchResult = searchResult;
}
searchService.get = function(text){
return mySearchResult;
}
return searchService;
});
CONTROLLER
myApp.controller('OnlineCVController', function($scope, searchService) {
$scope.searchPerson = function(personString) {
$.ajax({
url: "mySearch.php",
type: 'POST',
data: { Person: personString },
async: false, success: function (result) { searchService.set(result);
console.log(result);
window.location = "search.html";
}, error: function (result) { } });
}
Can anyone guide me further?

Passing the URL/route parameter from laravel and using in angular

I am new to Laravel 5 and angular.
I am using Laravel routing for traversal and backend operations and angular for just UI operations like fetching data and binding UI grid, etc.
I have following route defined in routes.php file below
routes.php
Route::pattern('clientid', '[0-9]+');
//used for AJAX call from angularjs and populating ui-grid
Route::get('getclients/{clientid?}', 'ClientController#getClients');
//used for displaying Laravel view with ui-grid
Route::get('client/{clientid?}', 'ClientController#showClients');
Please find the angular files:
app.js
var appClients = angular.module('getclients', ['clientsService', 'ui.grid', 'ui.grid.exporter', 'ui.grid.selection']);
clientController.js
appClients.controller('ClientsController', ['$scope', '$http', 'Client', '$interval', '$q', function ($scope, $http, Client, $interval, $q) {
/* Defining UI grid options*/
.
.
/* Calling service to fill the grid*/
Client.get(clientid)
.success(function (data, status, headers, config) {
if (data.length > 0) {
$scope.gridOptions.data = data;
}
});
}
clientsService.js
angular.module('clientsService', [])
.service('Client', function ($http) {
return {
// Get all the photos
get: function (clientid) {
if (clientid !== '') {
return $http.get('/myproject/public/getclients/' + clientid);
}
else {
return $http.get('/myproject/public/getclients/');
}
}
}
});
/*
**Note:**
Have already defined route in routes.php for using the same above:
Route::get('getclients/{clientid?}', 'ClientController#getClients');
*/
EXAMPLE:
Step 1:
Say I am hitting URL: http://<domain>/public/myproject/client/2
The following route would catch it and redirect to view where the ui-grid is present
Route::get('client/{clientid?}', 'ClientController#showClients');
Step 2:
Now, somehow need to figure out how to pass that **2** to angular so that I could pass that parameter while making ajax call and get grid data
I am confused as to how we could use the the url parameter from Laravel in angular?
I reckon that I am missing some concept or doing something wrong here.
Could anyone help me out?
Just a workaround to make it work with angular and without jquery.
From routes.php, the control is transferred to showClients action in ClientsController.php
ClientsController.php (Laravel Controller):
Passed the variable to Laravel view from controller using following statement:
public function showClients($clientid = '') {
return view('masters.clients', compact('clientid'));
}
Clients.php (Laravel View)
Added clientidmodel as ng-model and initialized it with passed clientid from Laravel controller using ng-init
<div ng-app="">
<div ng-controller="ClientsController">
<input type="text" name="txtClientId" ng-model="clientidmodel" style="display: none;" ng-init="clientidmodel = '{!!$clientid!!}'"/>
</div>
</div>
clientController.js
Added the watch to the angular model so that we can capture the initial value passed.
$scope.$watch("clientidmodel", function () {
Client.get($scope.clientidmodel)
.success(function (data, status, headers, config) {
if (data.length > 0) {
$scope.gridOptions.data = data;
}
});
});
Not sure whether this is the efficient way but as of now got the things working with this workaround.
Please let me know in case of any better way to approach the same.
You can achieve this in jquery by
var pathname = window.location.href;
var lastItem = pathname.split("/").pop(-1);
Note : Here you will get the last element
i.e.,
If your url is like yourapp.com/app#/product/15 then the script will return 15. That's the last element after / . You can change this according to your wish.
Then you can pass the value directly inside your Laravel Controller.
$.ajax({
type: "POST",
dataType: 'text',
crossOrigin : true,
data: {param : lastItem},
url: serviceUrl+'/getReceipeDetails',
})
.done(function( data ) {
var result = jQuery.parseJSON(data);
if(result.success==1)
{
$(".yourresult").html('Controller return success');
}
else
{
$(".yourresult").html('Controller return failure');
}
})
.fail( function(xhr, textStatus, errorThrown) {
console.log(errorThrown);
});

Data from firebase not loading on route change, but does on refresh

I'm using angularFire with Angular to update some views but the strange thing is when I switch from view to view the data doesn't load, but when I refresh the page it does. What's going on?
WizardController:
/* initialize data */
var ref = new Firebase('https://dlwj.firebaseio.com/');
/* set data to automatically update on change */
$scope.currentLocation = $route.current.$$route.originalPath;
$scope.propertyRef = $firebase(ref);
$scope.propertyRef.$on('loaded', function(value) {
//value will be undefined when I switch views using hash routes.
//there is no issue when I just refresh on that page.
console.log(value);
$scope.propertyConfiguration = value.products;
var products = [];
for (var key in value.products) {
if (value.products.hasOwnProperty(key)) {
products.push(key);
}
}
$scope.productsArray = products;
});
console.log('Data retrieved');
Routes:
$routeProvider.when('/SharedProperties',
{
templateUrl: 'partials/SharedPropertiesPartial.html',
controller: 'WizardController'
});
$routeProvider.when('/Registration',
{
templateUrl: 'partials/Registration.html',
controller: 'WizardController'
});
$routeProvider.when('/Login',
{
templateUrl: 'partials/Login.html',
controller: 'WizardController'
});
There is no reason to download the data using a wrapper lib like $firebase (which takes care of synchronization and such) and then immediately pull that data out and put it into a different scope object.
Just declare your scope var:
$scope.products = $firebase(ref);
And to use it:
<ul>
<li ng-repeat="product in products | orderByPriority">{{product|json}}</li>
</ul>
If you need to iterate the data in a controller or service:
$scope.products = $firebase(ref);
// some time later, probably in $scope.products.$on('loaded')...
// note that $getIndex() is only useful here to get the keys in
// the order they appear in the database, otherwise, forEach($scope.products, ...)
// is sufficient
angular.forEach($scope.products.$getIndex(), function(key) {
console.log(key, $scope.products[key]);
});
If you want to use Firebase as a static database (which is quite baffling to a lover of all things real-time like myself) and not be notified each time there is a change, you can simply do the following:
angular.controller('MyController', function($timeout, $scope) {
new Firebase('<URL>').once('value', function(snap) {
$timeout(function() {
$scope.products = snap.val();
});
});
});
And then utilize it normally:
<ul>
<li ng-repeat="(key,product) in products">{{key}}: {{product|json}}</li>
</ul>

Proper place for data-saving logic in AngularJS

App design question. I have a project which has a very large number of highly customized inputs. Each input is implemented as a directive (and Angular has made this an absolute joy to develop).
The inputs save their data upon blur, so there's no form to submit. That's been working great.
Each input has an attribute called "saveable" which drives another directive which is shared by all these input types. the Saveable directive uses a $resource to post data back to the API.
My question is, should this logic be in a directive at all? I initially put it there because I thought I would need the saving logic in multiple controllers, but it turns out they're really happening in the same one. Also, I read somewhere (lost the reference) that the directive is a bad place to put API logic.
Additionally, I need to introduce unit testing for this saving logic soon, and testing controllers seems much more straightforward than testing directives.
Thanks in advance; Angular's documentation may be… iffy… but the folks in the community are mega-rad.
[edit] a non-functional, simplified look at what I'm doing:
<input ng-model="question.value" some-input-type-directive saveable ng-blur="saveModel(question)">
.directive('saveable', ['savingService', function(savingService) {
return {
restrict: 'A',
link: function(scope) {
scope.saveModel = function(question) {
savingService.somethingOrOther.save(
{id: question.id, answer: question.value},
function(response, getResponseHeaders) {
// a bunch of post-processing
}
);
}
}
}
}])
No, I don't think the directive should be calling $http. I would create a service (using the factory in Angular) OR (preferably) a model. When it is in a model, I prefer to use the $resource service to define my model "classes". Then, I abstract the $http/REST code into a nice, active model.
The typical answer for this is that you should use a service for this purpose. Here's some general information about this: http://docs.angularjs.org/guide/dev_guide.services.understanding_services
Here is a plunk with code modeled after your own starting example:
Example code:
var app = angular.module('savingServiceDemo', []);
app.service('savingService', function() {
return {
somethingOrOther: {
save: function(obj, callback) {
console.log('Saved:');
console.dir(obj);
callback(obj, {});
}
}
};
});
app.directive('saveable', ['savingService', function(savingService) {
return {
restrict: 'A',
link: function(scope) {
scope.saveModel = function(question) {
savingService.somethingOrOther.save(
{
id: question.id,
answer: question.value
},
function(response, getResponseHeaders) {
// a bunch of post-processing
}
);
}
}
};
}]);
app.controller('questionController', ['$scope', function($scope) {
$scope.question = {
question: 'What kind of AngularJS object should you create to contain data access or network communication logic?',
id: 1,
value: ''
};
}]);
The relevant HTML markup:
<body ng-controller="questionController">
<h3>Question<h3>
<h4>{{question.question}}</h4>
Your answer: <input ng-model="question.value" saveable ng-blur="saveModel(question)" />
</body>
An alternative using only factory and the existing ngResource service:
However, you could also utilize factory and ngResource in a way that would let you reuse some of the common "saving logic", while still giving you the ability to provide variation for distinct types of objects / data that you wish to save or query. And, this way still results in just a single instantiation of the saver for your specific object type.
Example using MongoLab collections
I've done something like this to make it easier to use MongoLab collections.
Here's a plunk.
The gist of the idea is this snippet:
var dbUrl = "https://api.mongolab.com/api/1/databases/YOURDB/collections";
var apiKey = "YOUR API KEY";
var collections = [
"user",
"question",
"like"
];
for(var i = 0; i < collections.length; i++) {
var collectionName = collections[i];
app.factory(collectionName, ['$resource', function($resource) {
var resourceConstructor = createResource($resource, dbUrl, collectionName, apiKey);
var svc = new resourceConstructor();
// modify behavior if you want to override defaults
return svc;
}]);
}
Notes:
dbUrl and apiKey would be, of course, specific to your own MongoLab info
The array in this case is a group of distinct collections that you want individual ngResource-derived instances of
There is a createResource function defined (which you can see in the plunk and in the code below) that actually handles creating a constructor with an ngResource prototype.
If you wanted, you could modify the svc instance to vary its behavior by collection type
When you blur the input field, this will invoke the dummy consoleLog function and just write some debug info to the console for illustration purposes.
This also prints the number of times the createResource function itself was called, as a way to demonstrate that, even though there are actually two controllers, questionController and questionController2 asking for the same injections, the factories get called only 3 times in total.
Note: updateSafe is a function I like to use with MongoLab that allows you to apply a partial update, basically a PATCH. Otherwise, if you only send a few properties, the entire document will get overwritten with ONLY those properties! No good!
Full code:
HTML:
<body>
<div ng-controller="questionController">
<h3>Question<h3>
<h4>{{question.question}}</h4>
Your answer: <input ng-model="question.value" saveable ng-blur="save(question)" />
</div>
<div ng-controller="questionController2">
<h3>Question<h3>
<h4>{{question.question}}</h4>
Your answer: <input ng-model="question.value" saveable ng-blur="save(question)" />
</div>
</body>
JavaScript:
(function() {
var app = angular.module('savingServiceDemo', ['ngResource']);
var numberOfTimesCreateResourceGetsInvokedShouldStopAt3 = 0;
function createResource(resourceService, resourcePath, resourceName, apiKey) {
numberOfTimesCreateResourceGetsInvokedShouldStopAt3++;
var resource = resourceService(resourcePath + '/' + resourceName + '/:id',
{
apiKey: apiKey
},
{
update:
{
method: 'PUT'
}
}
);
resource.prototype.consoleLog = function (val, cb) {
console.log("The numberOfTimesCreateResourceGetsInvokedShouldStopAt3 counter is at: " + numberOfTimesCreateResourceGetsInvokedShouldStopAt3);
console.log('Logging:');
console.log(val);
console.log('this =');
console.log(this);
if (cb) {
cb();
}
};
resource.prototype.update = function (cb) {
return resource.update({
id: this._id.$oid
},
angular.extend({}, this, {
_id: undefined
}), cb);
};
resource.prototype.updateSafe = function (patch, cb) {
resource.get({id:this._id.$oid}, function(obj) {
for(var prop in patch) {
obj[prop] = patch[prop];
}
obj.update(cb);
});
};
resource.prototype.destroy = function (cb) {
return resource.remove({
id: this._id.$oid
}, cb);
};
return resource;
}
var dbUrl = "https://api.mongolab.com/api/1/databases/YOURDB/collections";
var apiKey = "YOUR API KEY";
var collections = [
"user",
"question",
"like"
];
for(var i = 0; i < collections.length; i++) {
var collectionName = collections[i];
app.factory(collectionName, ['$resource', function($resource) {
var resourceConstructor = createResource($resource, dbUrl, collectionName, apiKey);
var svc = new resourceConstructor();
// modify behavior if you want to override defaults
return svc;
}]);
}
app.controller('questionController', ['$scope', 'user', 'question', 'like',
function($scope, user, question, like) {
$scope.question = {
question: 'What kind of AngularJS object should you create to contain data access or network communication logic?',
id: 1,
value: ''
};
$scope.save = function(obj) {
question.consoleLog(obj, function() {
console.log('And, I got called back');
});
};
}]);
app.controller('questionController2', ['$scope', 'user', 'question', 'like',
function($scope, user, question, like) {
$scope.question = {
question: 'What is the coolest JS framework of them all?',
id: 1,
value: ''
};
$scope.save = function(obj) {
question.consoleLog(obj, function() {
console.log('You better have said AngularJS');
});
};
}]);
})();
In general, things related to the UI belong in a directive, things related to the binding of input and output (either from the user or from the server) belong in a controller, and things related to the business/application logic belong in a service (of some variety). I've found this separation leads to very clean code for my part.

Resources