I have a pins table in my database with a pin_date column.
In my migration I have this:
$table->dateTime('pin_date')->nullable();
I have a button that points to a post route
Route::post('/pins/pin-date/{id}', 'PinsController#pinDate');
that leads to a pinDate controller method:
public function pinDate($id)
{
$pin = Pin::find($id);
$pin->save();
}
I want to update the pin-date column in the database to the current date and time when I click the button and hit the route. I am not really sure how to do this. Any help would be greatly appreciated! Thank you!
I would do this whenever the model is saving, you can bind to the boot function of the model and set it there:
public static function boot()
{
parent::boot();
static::saving(function($pin) {
$pin->pin_date = \Carbon::now()
});
}
If you want to update this value instead of handling it whenever the model is saved - such as through a button click, you can use Ajax. You will need 1.) a route, 2.) a click handler, 3.) an AJAX request and 4.) a controller to handle processing the request:
Click handler with Ajax:
$('.btn').on('click', function(e) {
$.ajax({
url: '/route/to/update/my/pin' + $(this).closest('.pin').data('id')
});
});
Then a route:
Route::post('/route/to/update/my/pin/{id}', 'PinController#updatePinDate');
Then make the controller method and update it accordingly:
public function updatePinDate(Request $request, Pin $pin)
{
$pin->pin_date = \Carbon::now();
$pin->save();
}
If you don't want to use javascript, you can just use a standard form with the same route/controller methods:
<form action="/route/to/update/my/pin/{{ $pin->id }}" method="POST">
{{csrf_field()}}
<button type="Submit"> Update Pin Date </button>
</form>
public function pinDate($id)
{
$pin = Pin::find($id);
$pin->pin_date = \Carbon\Carbon::now();
$pin->save();
}
I hope it works.
I going to show my problem with an example:
I have a button. When clicked, it creates a mail draft based on the TextInputFields in the add-on.
I have a validate function, which can say if the fields filled right or not.
If I want to notify the user somehow about the wrong fields, I have to create a notify or rebuild the card with error information. These actions can be returned in a normal Action, but not with a composeAction (because composeAction has to return with builded draft), so I have to register a composeAction and a simple action to the button.
When I clicked this kind of button, only one of the action execute and the other do nothing.
Some code about how I tried to implement:
section.addWidget(CardService.newTextButton()
.setText('Validate and Create')
.setComposeAction(CardService.newAction().setFunction('doIt'), CardService.ComposedEmailType.STANDALONE_DRAFT)
.setOnClickAction(CardService.newAction().setFunction('notify')));
ActionFunctions:
function doIt(event){
validate the event['formInput'] object;
if(valid the formInput)
create andr return the draft;
else
return null;
}
function notify(event){
validate the event['formInput'] object;
if(valid the formInput)
return null;
else
return notify or rebuilded card with error info;
}
Mostly the simple action run, and the compose do nothing. If I place Logger.log() functions in the callback function, only one appears on api log.
Anyone have tried before validate and create draft at the same click?
How about this:
var action=CardService.newAction().setFunctionName('myFunction');
var validateCreateButton=CardService.newTextButton()
.setText('Validate & Create')
.setOnClickAction(action);
section.addWidget(validateCreateButton);
function myFunction(e) {
doit(e);
notify(e);
}
Currently, I am working on Angular 4 app. In my component Html, I have one textbox. Whenever user first type anything I want to make an API call to get some data.
The issue is if User type 'A' then it is working fine and calling API. But when user type "ABC" it is making API call 3 times. Instead of making API call for every letter, only one call should be made.
Please suggest any solution.
Component's HTML :
<input id="inputbox" (keyup)="keyUp($event)"/>
Component :
data: string[]
keyUp(event: any) {
this.loadDataApiCall();
}
loadDataApiCall() {
// calling api to load data.
//fill data into
}
Can I solve this issue with help of RXjs in angular 4
Observable.fromEvent(yourDomElement, 'keyup').auditTime(100).subscribe(()=>{
doSomething();
});
You should probably add a timeout to your call and clear it every time it is triggered so only the last call is called.
data: string[]
keyUp(event: any) {
window.clearTimeout(window.apiCallTimeout);
window.apiCallTimeout = window.setTimeout(this.loadDataApiCall, 100);
}
loadDataApiCall() {
// calling api to load data.
//fill data into
}
This means of course that the call will be done 100ms after the user stops typing. Also if he types "a" and after a while he types "bc", then two calls will be made. Of course you can increase the delay to meet your requirements.
If you only want one API call you can use the blur event, which is emitted when the control loses focus:
<input id="inputbox" (blur)="keyUp($event)"/>
Try this:
keyUp(event: any) {
this.loadDataApiCall();
event.stopImmediatePropagation();
}
the right way to implement this is by registering the event and calling the API after sometime while saving the latest value and checking that the last registered value matches the latest registered value
so in your keyup
keyUp(event: any) {
this.latestValue = event.target.value;
this.registerApiCall(event.target.value);
}
register func
registerApiCall(value){
setTimeout(this.loadDataApiCall.bind(this), 500, value)
}
api call
loadDataApiCall(value) {
if (this.latestValue == value ){
// calling api to load data.
//fill data into
}
}
see working example in this plnk
EDIT:
Observable.fromEvent(yourDomElement, 'keyup').auditTime(100).subscribe(()=>{
doSomething();
});
by éæšć is the RxJs implementation that looks much better, and here is a working plnkr
If you're willing to change your form to Reactive Forms this would be extremely easy
this.form.get("input").valueChanges.debounceTime(1000).subscribe((value) => {});
Reactive Forms gives you access to observables of value changes and status changes. We're basically subscribing to that observable which emits the value any time it changes and we add a delay of one second so that if the user is still typing and changing the value then it will not execute the code in our subscribe.
#Component({
selector: 'my-app',
template: `
<div>
<input type="text" (keyup)='keyUp.next($event)'>
</div>
,
})
export class App {
name:string;
public keyUp = new Subject<string>();
constructor() {
const subscription = this.keyUp
.map(event => event.target.value)
.debounceTime(1000)
.distinctUntilChanged()
.flatMap(search => Observable.of(search).delay(500))
.subscribe(console.log);
}
}
I am trying to understand how to do the following things:
What is the accepted way of declaring a form. My understanding is you just declare the form in HTML, and add ng-model directives like so:
ng-model="item.name"
What to send to the server. I can just send the item object to the server as JSON, and interpret it. Then I can perform validation on object. If it fails, I throw a JSON error, and send back what exactly? Is there an accepted way of doing this? How do I push validation errors from the server to the client in a nice way?
I really need an example, but Angulars docs are pretty difficult to understand.
Edit: It seems I've phrased my question poorly.
I know how to validate client side, and how to handle error/success as promise callbacks. What I want to know, is the accepted way of bundling SERVER side error messages to the client. Say I have a username and password signup form. I don't want to poll the server for usernames and then use Angular to determine a duplicate exists. I want to send the username to the server, validate no other account exists with the same name, and then submit form. If an error occurs, how do I send it back?
What about pushing the data to the server as is (keys and values) with an error field appended like so:
{
...data...
"errors": [
{
"context": null,
"message": "A detailed error message.",
"exceptionName": null
}
]
}
Then binding to the DOM.
I've also been playing around with this kind of thing recently and I've knocked up this demo. I think it does what you need.
Setup your form as per normal with any particular client side validations you want to use:
<div ng-controller="MyCtrl">
<form name="myForm" onsubmit="return false;">
<div>
<input type="text" placeholder="First name" name="firstName" ng-model="firstName" required="true" />
<span ng-show="myForm.firstName.$dirty && myForm.firstName.$error.required">You must enter a value here</span>
<span ng-show="myForm.firstName.$error.serverMessage">{{myForm.firstName.$error.serverMessage}}</span>
</div>
<div>
<input type="text" placeholder="Last name" name="lastName" ng-model="lastName"/>
<span ng-show="myForm.lastName.$error.serverMessage">{{myForm.lastName.$error.serverMessage}}</span>
</div>
<button ng-click="submit()">Submit</button>
</form>
</div>
Note also I have added a serverMessage for each field:
<span ng-show="myForm.firstName.$error.serverMessage">{{myForm.firstName.$error.serverMessage}}</span>
This is a customisable message that comes back from the server and it works the same way as any other error message (as far as I can tell).
Here is the controller:
function MyCtrl($scope, $parse) {
var pretendThisIsOnTheServerAndCalledViaAjax = function(){
var fieldState = {firstName: 'VALID', lastName: 'VALID'};
var allowedNames = ['Bob', 'Jill', 'Murray', 'Sally'];
if (allowedNames.indexOf($scope.firstName) == -1) fieldState.firstName = 'Allowed values are: ' + allowedNames.join(',');
if ($scope.lastName == $scope.firstName) fieldState.lastName = 'Your last name must be different from your first name';
return fieldState;
};
$scope.submit = function(){
var serverResponse = pretendThisIsOnTheServerAndCalledViaAjax();
for (var fieldName in serverResponse) {
var message = serverResponse[fieldName];
var serverMessage = $parse('myForm.'+fieldName+'.$error.serverMessage');
if (message == 'VALID') {
$scope.myForm.$setValidity(fieldName, true, $scope.myForm);
serverMessage.assign($scope, undefined);
}
else {
$scope.myForm.$setValidity(fieldName, false, $scope.myForm);
serverMessage.assign($scope, serverResponse[fieldName]);
}
}
};
}
I am pretending to call the server in pretendThisIsOnTheServerAndCalledViaAjax you can replace it with an ajax call, the point is it just returns the validation state for each field. In this simple case I am using the value VALID to indicate that the field is valid, any other value is treated as an error message. You may want something more sophisticated!
Once you have the validation state from the server you just need to update the state in your form.
You can access the form from scope, in this case the form is called myForm so $scope.myForm gets you the form. (Source for the form controller is here if you want to read up on how it works).
You then want to tell the form whether the field is valid/invalid:
$scope.myForm.$setValidity(fieldName, true, $scope.myForm);
or
$scope.myForm.$setValidity(fieldName, false, $scope.myForm);
We also need to set the error message. First of all get the accessor for the field using $parse. Then assign the value from the server.
var serverMessage = $parse('myForm.'+fieldName+'.$error.serverMessage');
serverMessage.assign($scope, serverResponse[fieldName]);
I've got similar solution as Derek, described on codetunes blog. TL;DR:
display an error in similar way as in Derek's solution:
<span ng-show="myForm.fieldName.$error.server">{{errors.fieldName}}</span>
add directive which would clean up an error when user change the input:
<input type="text" name="fieldName" ng-model="model.fieldName" server-error />
angular.module('app').directive 'serverError', ->
{
restrict: 'A'
require: '?ngModel'
link: (scope, element, attrs, ctrl) ->
element.on 'change', ->
scope.$apply ->
ctrl.$setValidity('server', true)
}
Handle an error by passing the error message to the scope and telling that form has an error:
errorCallback = (result) ->
# server will return something like:
# { errors: { name: ["Must be unique"] } }
angular.forEach result.data.errors, (errors, field) ->
# tell the form that field is invalid
$scope.form[field].$setValidity('server', false)
# keep the error messages from the server
$scope.errors[field] = errors.join(', ')
Hope it would be useful :)
Well, the Answer Derek Ekins gave is very nice to work on. But: If you disable the submit button with ng-disabled="myForm.$invalid" - the button will not automatically go back to enabled as the server-based error state doesn't seem to be changed. Not even if you edit ALL fields in a form again to comply with valid inputs (based on client side validation).
By default, the form is submitted normally. If you don't provide a name property for each field in the form then it won't submit the correct data. What you can do is capture the form before it submitted and submit that data yourself via ajax.
<form ng-submit="onSubmit(); return false">
And then in your $scope.onSubmit() function:
$scope.onSubmit = function() {
var data = {
'name' : $scope.item.name
};
$http.post(url, data)
.success(function() {
})
.failure(function() {
});
};
You can also validate the data by setting up required attributes.
If you choose ngResource, it would look like this
var Item = $resource('/items/');
$scope.item = new Item();
$scope.submit = function(){
$scope.item.$save(
function(data) {
//Yahooooo :)
}, function(response) {
//oh noooo :(
//I'm not sure, but your custom json Response should be stick in response.data, just inspect the response object
}
);
};
The most important thing is, that your HTTP-Response code have to be a 4xx to enter the failure callback.
As of July 2014, AngularJS 1.3 has added new form validation features. This includes ngMessages and asyncValidators so you can now fire server side validation per field prior to submitting the form.
Angular 1.3 Form validation tutorial :
Taming forms in Angular 1.3
Video | Repo | Demo
References:
ngMessages directive
ngModel.NgModelController
I needed this in a few projects so I created a directive. Finally took a moment to put it up on GitHub for anyone who wants a drop-in solution.
https://github.com/webadvanced/ng-remote-validate
Features:
Drop in solution for Ajax validation of any text or password input
Works with Angulars build in validation and cab be accessed at formName.inputName.$error.ngRemoteValidate
Throttles server requests (default 400ms) and can be set with ng-remote-throttle="550"
Allows HTTP method definition (default POST) with ng-remote-method="GET"
Example usage for a change password form that requires the user to enter their current password as well as the new password.:
Change password
Current
Required
Incorrect current password. Please enter your current account password.
<label for="newPassword">New</label>
<input type="password"
name="newPassword"
placeholder="New password"
ng-model="password.new"
required>
<label for="confirmPassword">Confirm</label>
<input ng-disabled=""
type="password"
name="confirmPassword"
placeholder="Confirm password"
ng-model="password.confirm"
ng-match="password.new"
required>
<span ng-show="changePasswordForm.confirmPassword.$error.match">
New and confirm do not match
</span>
<div>
<button type="submit"
ng-disabled="changePasswordForm.$invalid"
ng-click="changePassword(password.new, changePasswordForm);reset();">
Change password
</button>
</div>
As variant
// ES6 form controller class
class FormCtrl {
constructor($scope, SomeApiService) {
this.$scope = $scope;
this.someApiService = SomeApiService;
this.formData = {};
}
submit(form) {
if (form.$valid) {
this.someApiService
.save(this.formData)
.then(() => {
// handle success
// reset form
form.$setPristine();
form.$setUntouched();
// clear data
this.formData = {};
})
.catch((result) => {
// handle error
if (result.status === 400) {
this.handleServerValidationErrors(form, result.data && result.data.errors)
} else {// TODO: handle other errors}
})
}
}
handleServerValidationErrors(form, errors) {
// form field to model map
// add fields with input name different from name in model
// example: <input type="text" name="bCategory" ng-model="user.categoryId"/>
var map = {
categoryId: 'bCategory',
// other
};
if (errors && errors.length) {
// handle form fields errors separately
angular.forEach(errors, (error) => {
let formFieldName = map[error.field] || error.field;
let formField = form[formFieldName];
let formFieldWatcher;
if (formField) {
// tell the form that field is invalid
formField.$setValidity('server', false);
// waits for any changes on the input
// and when they happen it invalidates the server error.
formFieldWatcher = this.$scope.$watch(() => formField.$viewValue, (newValue, oldValue) => {
if (newValue === oldValue) {
return;
}
// clean up the server error
formField.$setValidity('server', true);
// clean up form field watcher
if (formFieldWatcher) {
formFieldWatcher();
formFieldWatcher = null;
}
});
}
});
} else {
// TODO: handle form validation
alert('Invalid form data');
}
}
As I understand the question is about passing errors from the server to the client. I'm not sure if there are well-established practices. So I'm going to describe a possible approach:
<form name="someForm" ng-submit="submit()" ng-controller="c1" novalidate>
<input name="someField" type="text" ng-model="data.someField" required>
<div ng-show="someForm.$submitted || someForm.someField.$touched">
<div ng-show="someForm.someField.$error.required" class="error">required</div>
<div ng-show="someForm.someField.$error.someError" class="error">some error</div>
</div>
<input type="submit">
</form>
Let's say a server returns an object of the following kind:
{errors: {
someField: ['someError'],
}}
Then you can pass the errors to the UI this way:
Object.keys(resp.errors).forEach(i => {
resp.errors[i].forEach(c => {
$scope.someForm[i].$setValidity(c, false);
$scope.someForm[i].$validators.someErrorResetter
= () => $scope.someForm[i].$setValidity(c, true);
});
});
I make each field invalid and add a validator (which is not really a validator). Since validators are called after every change, this let's us reset the error status.
You can experiment with it here. You might also want to check out ngMessages. And a couple of related articles.
in my asp.net mvc project I want an Action Redirect to a url but I want the page to open in new window.
public ActionResult Index(int id)
{
...
return Redirect(page.Url);
}
To open up a new window on client side you will have to do something either in View HTML or use some javascript. This can not be done in controller.
In view, you can set the target property of your action link from where this action is being called.
You should specify that the link will open in a new window using the target attribute on <a> element in the view i.e.
<a href="#Url.Action("Index", "Controller", new{ area = "", id = 1 })"
target= "_blank">Link text</a>
In the server side you can retrun json (after an ajax call usually)
public ActionResult PreviewReport(Report rep)
{
return Json(new { type = "info", url = "..." }, JsonRequestBehavior.AllowGet);
}
In the client side you execute javascript (the result is from an ajax call to above action)
function (result) {
if (result.type === 'info') {
window.open(result.url, '_blank');
}
}