This should be something trivial but I can't figure it out for the life of me.
What I need is an input field that is by default filled out for a user from a value from local Storage.
The problem I've run into is that none of the ways I'd normally do this (jQuery onload, JS onload or a (onload) in the HTML tag) seem to be run when a user switches to a different page without reloading. I've also tried ngOnInit() but that seems to be running before the page's DOM Content is ready to be edited and isn't working here.
Here is my code:
<form (submit)="editName($event)">
<div class="form-group">
<label for="nameInput">Name</label>
<!-- I want to insert the localStorage Value user_name into this input -->
<input type="name" class="form-control" id="nameInput" (onload)="initName()">
</div>
<button type="submit" class="btn btn-primary">Save changes</button>
</form>
A sad attempt at acheiving this is also in my component.ts:
initName() {
document.getElementById("nameInput").textContent = localStorage.getItem('user_name');
}
The error message in my console is:
ERROR TypeError: Cannot read property 'user_name' of undefined
I would recommend using an Angular ReactiveForm in this case instead of manually retrieving and binding the value.
In your component, create an instance of a FormGroup and bind the value from localStorage to the form control:
#Component({
template: `
<form *ngIf="form" [formGroup]="form" (submit)="editName($event)">
<div class="form-group">
<label for="nameInput">Name</label>
<input formControlName="name" type="name" class="form-control" id="nameInput">
</div>
<button type="submit" class="btn btn-primary">Save changes</button>
</form>
`
})
export class YourComponent implements OnInit {
form: FormGroup;
ngOnInit(): void {
this.form = new FormGroup({
name: new FormControl(localStorage.getItem('user_name')),
});
}
}
For more on Reactive forms in Angular, see: https://angular.io/guide/reactive-forms
I'd recommend using Angular Reactive Forms over Template-driven Forms regarding the purpose here. With a Template-driven approach you'll end up setting the localStorage bindings explicitly for every value inside your form. A better alternative is using Reactive Forms. (see Brandon's answer)
Assuming you use a FormGroup for your whole form you can retrieve and save the whole form using the FormGroup.value method that will give you all the values of your form in one step without disabled controls or FormGroup.getRawValue() to also include disabled controls. You can then just use this to store your attributes in the localStorage on form submit:
this.form = new FormGroup({
surName: new FormControl('user_surname'),
name: new FormControl('user_name'),
age: new FormControl('user_age'),
...
});
localStorage.setItem('userFormValues',JSON.stringify(this.form.value));
See how this example looks in your local storage:
This way your local storage will not be messed up with many keys. To read your values back to your form just use JSON.parse in combination with FormGroup.setValue():
this.form.setValue(JSON.parse(localStorage.getItem('userFormValues')));
TS page
init variable
username:string;
create function for fill variable from localstorage
getName(){
this.username = localStorage.getItem("user_name";
}
call variable on page load
onInit(){
this.getName();
}
html page
<input type="name" class="form-control" id="nameInput" value="{{username}}">
In the end I've gone with creating a method called getUsername() in component.ts:
getUsername() {
return localStorage.getItem('user_name');
}
then I bound it to the input using this:
<input type="name" class="form-control" id="nameInput" value="{{getUsername()}}">
Related
<!--html-->
<div id="vvv">
<form action="#">
<input required type="text">
<input type="submit" #submit="func">
</form>
</div>
// js
vvv = new Vue({
el: '#vvv',
methods: {
func(){
console.log(11111111111111)
}
}
})
How to make the function called by #submit work?
I need use the default submit action to inspect if all required fields have been filled. And after that, i wanna call my own submit function which set by #submit to post form data.
But, i find the function set by #submit is not be allowed to call.
What's wrong with my code? Or, if this action really not be allowed? And how can i realize my requirement?
Try calling the function from form tag
<!--html-->
<div id="vvv">
<form action="#" #submit.prevent="func" >
<input required type="text">
<button type="submit" >Submit</button>
</form>
</div>
If you're trying to do some custom validations, Vue makes it easy to track the state in real time. In the example I threw together below, you can see how a few different fields are simply validated to not be empty.
This is something you would build on, of course, to make more advanced validations, but hopefully it illustrates the concept. Then, you can use whatever method on whatever element you want to submit your form data!
https://codepen.io/barneychampaign/pen/JjKxymg
I read several answers on this topic but they don't seem to apply to my problem. My problem is quite complex. I have a form which uses ReportViewer.ASPX. The form is defined as following:
<form name="form" novalidate role="form"
sm-dirty-check
id="reportViewer"
method="post"
action="~/Infrastructure/ReportViewer/reportViewer.aspx"
target="viewerIFrame"
ng-show="crud.showForm" class="ng-cloak">
#* Form inputs *#
<input type="hidden" name="labelType" value="Rental" />
<input type="hidden" name="labelLayoutId" value="{{ crud.model.lbLayoutId }}" />
<input type="hidden" name="itemsToPrint" value="{{ crud.jsItemsToPrint }}" />
The actual forms are defined in the tabs using ng-form (I only shared the top portion of my Edit form which is relevant to my question).
I also have these buttons at the bottom of the form:
<button type="submit"
ng-if="crud.model.lbLayoutId!==0"
name="generateLabelButton"
id="generateLabelButton"
class="btn btn-primary pull-left"
ng-click="crud.generateLabel()"
ng-disabled="crud.isSaveButtonDisabled">
#Labels.generateLabel
</button>
<div class="pull-left generateLabelButton">
<data-desc:type ng-if="crud.model.lbLayoutId===0"
value="#Labels.generateLabel"
keep-pristine="true"
on-after-selection="crud.layoutSelected(selectedValue)"
title="{{ '#string.Format(Labels.selectX, Labels.labelLayout)'}}"
param="layouts"
message="#string.Format(Labels.selectX, Labels.labelLayout)"
selected="crud.model.lbLayoutId"
descrip-value="descrip"
id="layoutPickerButton"
name="layoutPickerButton"
button-type="button"
type="7"
filter-by="Label"
description="crud.model.lbLayout">
</data-desc:type>
</div>
So, if I have lblLayoutId defined, I have my regular submit button and I press it and get my form submitted and all is well.
If I don't have the lblLayoutId defined (it's 0), I need to use a directive which has a template for a button, when I press it, it opens a modal form to pick the layout, etc.
So, my problem is that after I picked the layout, I need to submit my form so the label can appear.
I tried making the directive to be of type submit (button-type property), this didn't work.
I also tried the following code in the method which is executed by the button when value is selected:
rentalEquipmentsCrudController.prototype.layoutSelected = function (selectedValue) {
this.model.lbLayoutId = selectedValue;
$("#generateLabelButton").click();
}
rentalEquipmentsCrudController.prototype.generateLabel = function () {
if (this.model.lbLayoutId === 0) return;
this.jsItemsToPrint = "";
this.itemsToPrint = this.getItemsToPrint();
this.jsItemsToPrint = JSON.stringify(this.itemsToPrint);
angular.element($("#viewerIFrame").contents()
.find("#reportViewer_ReportViewer")).empty();
let actionPath = angular.element($("#reportViewer")).attr("action");
if (actionPath.slice(-3) !== "pdf") actionPath += "/Labels.pdf";
angular.element($("#reportViewer")).attr("action", actionPath);
this.showViewer = true;
};
The layoutSelected method is executed from my directive and the next code is executed by my regular button.
So, I'm at lost as how to make it work.
The role of forms in client-side AngularJS applications is different than in classical roundtrip apps, it is desirable for the browser not to translate the form submission into a full page reload. Instead post JSON data and receive JSON data responses. Go to the server for data, but not html/js/css etc.
Read AngularJS <form> Directive API Reference - Submitting a form and preventing the default action.
You don't want to combine ng-click with a button of type="submit", this will still cause the form to submit (non-programmatically). Instead, use type="button". Alternatively, you can keep type="submit" but add the ng-submit="crud.generateLabel()" to the form element
<form>
...
<button type="button" ng-click="crud.generateLabel()">...</button>
</form>
Alternatively:
<form ng-submit="crud.generateLabel()">
...
<button type="submit">...</button>
</form>
I'm trying to download a file with an html.actionlink(text, action, controller, reoute values, htmlattributes)
I'm trying to pass the view model and text from an <input type="text" to the controller. But I'm having trouble passing the input text to the MVC controller. I'm using an actionlink because I can't seem to download the file with post
How can I pass the Model values and the text input to the controller?
This is the HTML
<body>
<div class="col-md-12 form-group centered">
<div class="col-md-4"></div>
<div class="col-md-4">
<label for="quoted">Quoted:</label>
<input type="text" class="form-control" style="width:300px" id="quoted">
</div>
<div class="col-md-4"></div>
</div>
<div class="col-md-12 text-center">
#Html.ActionLink("Download", "GeneratePoExportDocument", "HealthCareExport", new {model = Model, quoted = "text box input goes here" }, new { #class = "btn btn-default", id="download-btn" })
</div>
Are there other methods to download a file where I can pass in all the values?
</body>
Here is the controller
public FileResult GeneratePoExportDocument(MyModel model, string quoted)
{
//my model has all of the values
//quoted is null I don't know how to pass that in
}
You cannot, and should not pass your entire model like that in the querystring. The textbox in part of the rendered HTML and user can enter any value there. So if you want to send that data, either you have to hijack the click event of your link using javascript, read the input element value and append that to the querystring and navigate to that url by setting window.location.href value.
Another (more solid IMHO) option is to do a form submit. If you want to send certain properties of your view model, you may include them as hidden input in the form
<form action="#Url.Action("GeneratePoExportDocument","HealthCareExport")" method="post">
#Html.HiddenFor(a => a.Id)
#Html.HiddenFor(a => a.CartId)
<label for="quoted">Quoted:</label>
<input type="text" class="form-control" style="width:300px" name="quoted">
<button type="submit">Download</button>
</form>
Send only the proeprties you absolutely want in the action method. If all you need is theId, send only that. Perhaps you can rebuild your entire model in that action method from the Id if needed.
Try doing this with Javascript:
Replace your ActionLink with this:
<a href="#Url.Action('GeneratePoExportDocument', 'HealthCareExport', new {model = Model, quoted = 'placeholder'})" id='myLink'>Download</a>
Then use blur function in javascript for the textbox.
$("#quoted").blur(function() {
var currentUri = $("#myLink").attr("href");
var newUri = currentUri.replace("placeholder", $(this).val());
$("#myLink").attr('href', newUri);
});
Let me know if this helps.
In my Angular 1.5.X app I have a directive with the following template
<form id="pdfDownloadForm"
name='pdfDownloadForm'
method="POST"
action="{{ downloadUrl }}">
<input type="hidden" name="data" value="" />
<button type="button" ng-click="submit()">Submit</button>
</form>
When the form is submitted, I would like to do the following
Set the value of the hidden parameter data to a value retrieved from a remote service
Submit the form
Attempted Solution
Presumably the easiest way to set the hidden parameter is with
<input type="hidden" name="data" ng-model="dataValue" />
and then before submitting the form, assign to scope.dataValue the value retrieved from the remote service?
I tried to submit the form programmatically with
scope.submit = function () {
$('#pdfDownloadForm').submit();
}
But this causes the following error:
Error: [$rootScope:inprog] $apply already in progress
Since you're using Angular 1.5+, there's no reason to use scope - either use controllerAs syntax or, preferably, components.
I'd implement your task by interrupting first submit call and populating hidden field instead. Any subsequent submits are allowed to happen.
// inside contorller
onSubmit(event) {
if (!this.dataValue) {
event.preventDefault();
this.initializeData();
}
}
initializeData() {
$http.get('/my-data-source').then((response) => {
this.dataValue = response.data.value;
this.pdfDownloadForm.submit(); // requires <form name="$ctrl.pdfDownloadForm">
});
}
See https://docs.angularjs.org/api/ng/directive/ngSubmit
It's better to avoid using ngClick here since form can be submitted by Enter instead of button click.
<button type="button" ng-click="submit">Submit</button>
should be
<button type="button" ng-click="submit()">Submit</button>
so after your edit to your post, this wasn't the solution? have your tried it?
Having these two files:
HTML:
<form name="registrationForm" ng-submit="registerUser()">
...
</form>
JS (inside the Angular controller):
$scope.registrationForm.confirmPassword.$setValidity("PasswordsMatch", $scope.validation.doPasswordsMatch);
I get the error that Cannot read property 'confirmPassword' of undefined
This leads me to believe that I have no access to the form registrationForm in the controller. Based on this (https://docs.angularjs.org/api/ng/type/ngModel.NgModelController) I imagined that I should.
Other solutions that I've seen include passing the form to the controller when the form is submitted, but what I need to do (set custom validation) needs to happen way before that.
Other solution mentioned adding the controller to the form via ng-controller but that changed nothing.
EDIT:
From the website above, is there a reason why in here (https://plnkr.co/edit/ZT0G6ajdbescT72qLKSU?p=preview) $scope.myForm can be accessed, but only inside of the $scope.setEmpty function?
I recommend using the controller itself instead of the $scope provider for this. This was one of the first issues I came across when working with angularjs
In your controller:
function MyController($scope) {
var vm = this;
vm.registrationForm.confirmPassword.$setValidity("PasswordsMatch", $scope.validation.doPasswordsMatch);
}
In your form:
<form name="vm.registrationForm" ng-submit="registerUser()">
...
</form>
The only gotcha is that you need to specify the controllerAs property in your route or ngInclude:
ng-include="templates/my-template.html" ng-controller="MyController as vm"
or
when('/my-route', {
templateUrl: 'templates/my-template.html',
controller: 'MyController as vm'
})
You need to add a name attribute to form element.
<form name="registrationForm" ng-submit="registerUser()">
...
</form>
this form must rely on a controller indeed. please take a look at the example:
angular.module("fooApp",[]);
angular.module("fooApp")
.controller("formctl",function(){
this.user={};
this.dosave=function(){
if(this.user.pwd == this.user.confpwd)
alert(this.user.username+" logged");
else
alert("pwd does not match");
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="fooApp">
<h1>sample</h1>
<div ng-controller="formctl as ctl">
<form ng-submit="ctl.dosave()">
<label>username</label><br/>
<input ng-model="ctl.user.username" required/><br/>
<label>password</label><br/>
<input ng-model="ctl.user.pwd" type="password" required/><br/>
<label>confirm password</label><br/>
<input ng-model="ctl.user.confpwd" type="password"/><br/>
<input type="submit"/>
</form>
</div>
</div>
You'll want to pass the form into the submit function to pass the entire form into the controller. Use the form name.
<form name="registrationForm" ng-submit="registerUser(registrationForm)">
...
</form>
The other option would be to pass the inputs directly in as params
<form name="myForm" novalidate >
some input: <input type="text" name="sometext" ng-model="myInput">
<input type="submit" ng-click="doAction(myInput)">
</form>
Quick Plunk
https://plnkr.co/edit/s0Al2LTHkvUPoLYNzTpm?p=info
If you're just after the value of the inputs, it's easier to test if you have explicit parameters that you expect on the method instead of dumping in the entire form.