angularjs and grails 2.5.0 save success, no errors but not saving to database - angularjs

I've been looking for similar situations like mine has and I've seen that it is common to have this error but I can not find the right solution with my problem. I would really appreciate any help.
My problem right now is that when I execute this it return and HTTP 200 and also prints a line on my terminal which confirms me that it creates the JSON file. There are no errors but when I checked on my database, there's nothing in it.
What I've tried so far:
newBook.save(flush: true)
edit my datasource from create-drop to update (but my whole database disappears so I returned the data. I only need to save it during a demo so I understand that the data will be lost every time the application restarts)
Postman GET and POST
GET: 200 OK
POST: 200 OK
but when I GET again, nothing is showing
debugging using console and println (but there might be something that I missed since I'm just starting to learn both AngularJS and Grails)
I am hoping that these data can give a detailed information about my problem, I am open for any questions.
Here are my sample codes:
back-end codes: Grails 2.5.0
Domain class
class Book {
String name
int page
boolean new
static belongsTo = [student: student]
static constraints = {
}
}
Controller
import grails.converters.JSON
import org.springframework.security.access.annotation.Secured
#Secured('permitAll')
class BookController {
def index() {
render Book.list() as JSON
}
def save() {
def newBook = new Book(request.JSON)
newBook.save(flush: true)
println request.JSON
render(['success': true] as JSON)
}
def show() {
def Book = Book.get(params.id)
render Book as JSON
}
}
front-end codes: AngularJS
Controller
app.controller('Book', function($scope, store, $state, bookFactory){
$scope.book = {}
$scope.saveBook = function() {
$scope.book.assessment = $scope.getBook();
console.log($scope.book);
bookFactory.save($scope.book,function (result){
console.log(result)
}, function (error) {
console.log(error)
})
}
$scope.getBook = function() {
var result = "";
if ($scope.book.page > 10){
result = "many pages";
}else if ($scope.book.new && $scope.book.page > 20){
result = "new and many pages";
}else {
result = "old book";
}
return result;
};
})
Service
app.factory('bookFactory', ['$resource', function ($resource) {
return $resource('api/book',
{
'update': {method: 'PUT'}
})
}])
app.js
.state("book", {
url: "/book",
templateUrl: "assets/app/partials/book.html",
controller: 'Book',
data: {
requiresLogin: true
}
})
HTML
Book Name:
<input type="text" ng-model="book.name" name="bookName" required="" class="form-control" />
Number of Pages:
<input type="number" ng-model="book.page" name="numberPage" required="" class="form-control" placeholder="Number of Pages"/>
Bought within the last 30 days?
<div class="form-group">
<div class="radio">
<label>
<input type="radio" name="new" value=true ng-model="book.new" >
<font color=green>YES</font>
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="new" value=false ng-model="book.new">
<font color=red>NO</font>
</label>
</div>
</div>
<a ui-sref="book" class="btn btn-primary" name="bookBtn" ng-click="saveBook()"> Next </a>

Related

How to pass a model to AngularJS fileuploader?

I want to upload few files to server with angularjs-file-uploader. I have an array of viewModels, I want to upload files and get the IDs of uploaded files and assign them to corresponding viewModels.
Is there any way to pass my viewModels to fileUploader? Here are the codes I have written so far.
<div ng-if="vm.isFile(v.formItem)" class="form-group form-md-line-input form-md-floating-label no-hint">
<div class="form-group">
<input type="file" name="v.id" nv-file-select uploader="vm.uploader" />
<span class="help-block m-b-none">{{v.formItem.description}}</span>
</div>
</div>
I want to pass a "v.formItem" which has a property for uploadedFileId. so that I can assign uploaded file's Id to my Model.
this.uploader = new FileUploader({
url: 'File/UploadFile',
autoUpload: true,
removeAfterUpload: true,
queueLimit: 1
});
this.uploader.onSuccessItem = function (fileItem, response, status, headers) {
if (response.success) {
formItem.uploadedFileId = response.result.id ;
}
};
I found the solution. I just needed to use "options" property for file input. like this:
<input type="file" name="v.id" options={formItem:v.formItem} nv-file-select uploader="vm.uploader" />
javascript:
this.uploader.onSuccessItem = function (fileItem, response, status, headers) {
if (response.success) {
var formItem = fileItem.formItem;
formItem.uploadedFileId = response.result.id ;
}
};

Is this the correct way of binding factory to controller?

I have the following code in my module:
.controller('ModalInstanceCtrl', function($rootScope, $scope, emailService) {
$scope.emailService = emailService; // Good or not; if not, why?
$scope.showed = false;
$rootScope.$watch('showed', function () { $scope.showed = $rootScope.showed; }); // In case you wonder why I did this - I'm using this trick to prevent watch from firing twice, because that would happen if I remove the watch below and put its code here.
$scope.$watch('showed', function () {
if (!$rootScope.showed) return;
$scope.selected = 0;
$scope.primary = true;
$scope.verified = true;
if (emailService.emails.length == 0) emailService.load();
});
$scope.EmailSelected = function () {
emailService.setCurrent($scope.selected);
$scope.primary = emailService.emails[$scope.selected].primary;
$scope.verified = emailService.emails[$scope.selected].verified;
};
});
.factory('emailService', function($resource, $http) {
var emails = []; // [{email: 'sample#email.dom', verified: true, primary: false}, ...]
var selected = 0;
function sendreq(action, email){
$http({
method: 'POST',
url: '/email/',
data: "action_" + action + "=&email=" + email,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).then(function(response) {
console.log(response.data);
return true;
}, function(data){
return data;
});
}
return {
emails: emails,
selected: selected,
setCurrent: function(curr){
selected = curr;
},
load: function(){
$resource('/api/email/?format=json').query({},
function success(result) {
emails.push.apply(emails, result);
});
},
add: function(email) {
for (var e in emails) if (emails[e].email == email) return false;
return sendreq('add', email);
},
remove: function() {
sendreq('remove', emails[selected].email);
}
}
})
And this code in my HTML template:
<div ng-repeat="e in emailService.emails">
<input type="radio" ng-model="$parent.selected" ng-value="$index" ng-change="EmailSelected()" id="email_{{ $index }}" name="email">
<label for="email_{{ $index }}" ng-bind='e.email'></label> <span ng-show="e.verified">Verified</span> <span ng-show="e.primary">Primary</span>
</div>
<div><button ng-disabled="primary" ng-click="emailService.remove()">Remove</button></div>
<form novalidate>
<input class="form-control" type="email" name="email" ng-model="email" placeholder="Email">
<input type="submit" ng-disabled="email === undefined" ng-click="emailService.add(email)" value="Add Email Address">
</form>
And I want to ask, whether I've correctly assembled the module and template because I'm working with AngularJS for the first time. Specifically, I want to ask if it's correct to bind the whole factory to the scope? Also if someone has more time he can look at the other code to see if everything is right or not. Feel free to write any suggestions about my code.
Thanks in advance!
It always depends on particular case.
This way boilerplate wrapper methods
$scope.add = (...args) => emailService.add(...args);
can be omitted, as well as their tests in controller spec.
Another benefit is that it provides existing object for proper data binding and scope inheritance of scalar scope properties:
<parent-scope>
<p ng-init="emailService.selected = 0"></p>
<child-scope>
<p ng-init="emailService.selected = 1"></p>
{{ emailService.selected === $parent.emailService.selected }}
</child-scope>
</parent-scope>
This certainly would not work as expected if there's no emailService object. This is particularly useful when controllerAs syntax isn't used.
There's nothing wrong with exposing a service to scope - if its API matches the controller scope. And this may indicate an antipattern if it doesn't - or if there are too many services that are abused like that.
Why do you want to bind the entire service ? I do not see a need to that in your code. You are invoking parts of the service using the service handler, there is no specific need to put the entire service on scope.

Why angularjs controller is not called when i click the button again?

Hi i have a webpage like this,
left side has button,
right side is the area for ng-view (in my case, several checkboxes and submit button)
When i click the button, it'll
1. using the route provider, it'll reach its controller and template URL.
2. The controller will query some info from back end side (node.js)
3. The info above will be used by template URL to display initial checkbox options.
Now this procedure works fine for the 1st time. But when i click the button again, i was hoping it'll call its controller again, but from debugger, seems nothing happened, controller is not called.
So very confused, why is this please ???
in the server side,
app.get('/2getMyDiagValue', function(req, res)
{
console.log("get my diag");
var v1=0, v2=0;
var shellCmd = "... some executable ... ";
exec(shellCmd, function(error, stdout, stderr) {
if(error) {
console.log("Error running getting sid");
} else {
// get v1 and v2 from stdout
}
res.json( {"mystuff1":v1, "mystuff2":v2} );
});
app.post('/2setMyDiagValue', function(req, res)
{
// get the checkbox options from webpage,
// and save them in the backend
}
in the client side,
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.when('/5MyDiag', {
templateUrl: 'partials/MyDiag.html',
controller: 'MyDiagController'
});
}
]);
app.controller('myDiagController', function($scope, $http, $routeParams, QueryMyService) {
// using http.get() to get existing my setting from server side
QueryMyService.getInfoFromUrl7('/2getMyDiagValue').then(function(result) {
$scope.formData = result.formDataObjects;
}, function(error) {
alert("Error");
} );
$scope.submitForm = function() {
console.log("posting form data ...");
$http.post("/2setMyDiagValue",
JSON.stringify($scope.formData)).success(function(){} );
};
});
app.factory('QueryMyService', function($http, $q, $location) {
var factory = {};
var browserProtocol = 'http';
var address = 'localhost';
var server = browserProtocol + '://' + address;
//////////////////////////////////////////////////////////
factory.getInfoFromUrl7 = function(myUrl) {
var deferred = $q.defer();
$http.get(myUrl).success(function(data) {
deferred.resolve(data);
}).error(function(){
deferred.reject();
});
return deferred.promise;
}
return factory;
}
checkbox webpage itself: MyDiag.html
<form ng-submit="submitForm()" ng-controller="myDiagController">
<div class="control-group" style="color:black">
<label>My Checkbox</label>
<div class="checkbox">
<label class="checbox-inline" >
<input class="big-checkbox" type="checkbox" ng-model="formData.myStuff1"
ng-true-value="1" ng-false-value="0" ng-checked="formData.myStuff1 == 1">
<h4>Message 1</h4>
<input class="big-checkbox" type="checkbox" ng-model="formData.myStuff2"
ng-true-value="1" ng-false-value="0" ng-checked="formData.myStuff2 == 1">
<h4>Message 2</h4>
</label>
</div>
<br>
<input class="btn-primary" type="submit">
</form>
index.html
<div class="container">
<a class="btn btn-md btn-info custom-btn" ng-href="#/5MyDiag">Diagnostics</a>
</div>
Since i need to remove company names in the variable, there might be mismatch, but idea is the same. Thank you for your help.
Talked with guru, it's supposed to be so, if angular feels no change to the web GUI, e.g. in my case, i clicked the same button twice, it won't call the route provider again for the 2nd click.
If you knew this concept, you don't need to read my code to answer this question.
Wish i can get the 4 points back.

local vs hosted restful service. angular and codeigniter restserver

previously, i have a question here about posting data to the Restful service in php:
ionic restful authentication to POST and get data from php
now i have a weird bug. it is only occur on my hosted api. but when i change the url to my local,
http://localhost/my-serv/api/myrest/method
it is working, i get the alert showing my input data. but when i change it to my hosting url
http://my-domain.com/my-serv/api/myrest/method it does nothing.
this is all the things on my app:
var tapp = angular.module('tapp', ['ionic', 'ngCordova', 'restangular']);
var baseURL = 'http://localhost/my-serv/api/myrest/';
tapp.config(function($stateProvider, $urlRouterProvider, RestangularProvider){
$stateProvider
.state('tapp.test', {
url: '/tester',
views: {
'tappMenu':{
templateUrl: 'template/tester.html',
}
}
});
RestangularProvider.setBaseUrl(baseURL);
}
controller
tapp.controller('tCtrl', function($scope, $http, Restangular){
var posted = Restangular.all('posted');
$scope.inData = {};
$scope.tester = function(){
var posting = { name: $scope.inData.text };
posted.post(posting).then(function(re){
alert(re.values);
}, function(o){
alert(o);
});
};
});
html template
<ion-view title="TEST">
<ion-content ng-controller="tCtrl">
<form ng-submit="tester()">
<div class="list">
<label class="item item-input">
<input type="text" name="testing" ng-model="inData.text" placeholder="First Name">
</label>
</div>
<button type="submit" class="button button-block button-royal">Submit</button>
</form>
</ion-content>
php codeigniter rest server
<?php defined('BASEPATH') OR exit('No direct script access allowed');
require APPPATH.'/libraries/REST_Controller.php';
class Myrest extends REST_Controller
{
public function __construct()
{
parent::__construct();
//$this->methods['user_get']['limit'] = 500; //500 requests per hour per user/key
}
public function posted_post()
{
$ok = $this->post('name');
$arr = array('values'=>$ok);
$this->response($arr, 200);
}
}

Why isn't updated model's value, updated via service, changing in UI?

Below, summary and test are set via MyCtrl. I'm seeing "my test" display properly, but not "summary.name". I'm seeing that MySvc.get()'s callback executes as expected, but summary.name's updated value doesn't appear on the UI.
Any suggestions on why summary.name's updated value isn't appearing on the UI ?
app.js:
...
.state('tab.edit', {
url: '/edit',
views: {
'tab-dash': {
templateUrl: 'templates/MyTemplate.html',
controller: 'MyCtrl'
}
}
})
...
MyTemplate.html:
<label class="item item-input item-stacked-label">
<span class="input-label">Name</span>
<textarea rows="8" placeholder="Nothing yet." ng-model="summary.name"></textarea>
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">TEST</span>
<textarea rows="8" placeholder="Nothing yet." ng-model="test"></textarea>
</label>
controllers.js:
...
.controller('MyCtrl', function($scope, MySvc) {
console.log("MyCtrl: entered");
$scope.summary = MySvc.get(0);
$scope.test = "my test";
...
MySvc.get(0) returns ( and I see this callback execute and change ret.name ):
return $http.get(url).then(function(response) {
console.log("MySvc callback: response.data = %o", response.data);
console.log("MySvc callback: response.data.name = " + response.data.name);
ret = new MySvc(response.data);
console.log("MySvc callback: ret.name = " + ret.name);
return ret;
});
You treated the return value of MySvc.get as a synchronous (immediately available) value. What is received via the $http service is not available immediately, so you can't treat it as a simple return value.
What you'll really want to do is use it as a promise, which it (most likely) is:
MySvc.get(0)
.then(function(summary) {
$scope.summary = summary;
});
And you'll probably want to read up on promises, Chapters 1 to 3 of "You Don't Know JS - Async & Performance" are an excellent starting point.

Resources