Input not binding correctly with Vue.js - javascript

I'm still relatively new to Vue.js and am having an issue binding one of my inputs to my viewmodel.
Here is my JavaScript:
var viewModel = new Vue({
el: "#InventoryContainer",
data: {
upcCode: "",
component: {
Name: ""
}
},
methods: {
upcEntered: function (e) {
if (this.upcCode.length > 0){
$.ajax({
url: "/Component/GetByUpc",
type: "GET",
data: {
upc: this.upcCode
}
}).done(function (response) {
if (response.exists) {
$("#ComponentInformation").toggleClass("hidden");
this.component = response.component;
} else {
alert("No component found.");
}
});
}
}
}
});
Here is my HTML:
<div class="form-horizontal row">
<div class="col-sm-12">
<div class="form-group">
<label class="control-label col-md-4">UPC Code</label>
<div class="col-md-8">
<input id="ComponentUPC" class="form-control" placeholder="Scan or enter UPC Code" v-on:blur="upcEntered" v-model="upcCode" />
</div>
</div>
<div id="ComponentInformation" class="hidden">
<input type="text" class="form-control" readonly v-model="component.Name" />
</div>
</div>
</div>
Now the issue is that even when I enter a valid UPC code and I assign the component to my ViewModel, the input that is bound to component.Name does not update with the component name. And when I enter into the console viewModel.component.Name I can see that it returns "".
But if I put an alert in my ajax.done function after I've assigned the component and it looks like this alert(this.component.Name) it alerts the name of the component.
Any ideas of where I'm going wrong here?

You cannot use that line
this.component = response.component;
because of the this-variable.
You should put the line
var self = this
before your ajax call and use self.component instead of this.component

in order for vue to work you need to define the parent container with id InventoryContainer
<div id="InventoryContainer" class="form-horizontal row">
<div class="col-sm-12">
<div class="form-group">
....
here is the updated code: https://jsfiddle.net/hdqdmscv/
here is the updated fiddle based on your comment
https://jsfiddle.net/hdqdmscv/2/
(replace this with name of vue variable in ajax)

Related

How to set the same dropdown across multiple forms from ajax

I have multiple instances of the same form within different accordion elements. Each form represents a different project. I am trying to populate a dropdown on the form with a list of managers that is stored dynamically. I can only get the first dropdown instance to populate, and not the rest. How do I get all the instances of the manager dropdown to populate?
HTML
#foreach (Project project in Model.Projects)
{
<div class="accordion-item">
<h2 class="accordion-header" id="#("heading"+project.Key)">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" aria-expanded="false">
<b> #project.Number- </b>: #project.Name
</button>
</h2>
<div class="accordion-body">
<form>
<div class="mb-3 row">
<label for="manager" class="col-sm-1 col-form-label">Manager</label>
<div class="col-sm-3">
<select class="form-control capManager" asp-for="#project.Manager"></select>
</div>
<label for="budgetYear" class="col-sm-2 col-form-label" style="text-align: right">Budget Year</label>
<div class="col-sm-1">
<input type="text" class="form-control" asp-for="#project.BudgetYear">
</div>
<label for="budgetQuarter" class="col-sm-1 col-form-label">Quarter</label>
<div class="col-sm-1">
<input type="text" class="form-control" asp-for="#project.BudgetQuarter">
</div>
<div class="col-sm-3"></div>
</div>
</form>
</div>
</div>
}
Javascript
function populateManagerOptions() {
//Populate Manager options
$.ajax({
url: '/Lookup/GetProjManagerData/',
type: 'GET',
data: {
'reason': 'dropdown'
},
dataType: 'json',
success: function (json) {
const collection = document.getElementsByClassName("capManager");
for (let i = 0; i < collection.length; i++) {
$.each(json, function (i, value) {
collection[i].append($('<option>').text(value.mgrname).attr('value', value.projmgr));
});
}
}
});
}
Controller
[HttpGet]
public IActionResult GetProjManagerData(string reason)
{
try
{
IEnumerable<TblProjmgr> codes = _context.TblProjmgr.AsEnumerable();
if (reason == "dropdown")
return Json(codes);
else
return Json(new { data = codes });
}
catch (Exception ex)
{
_logger.LogError(ex, DateTime.Now + "- Error occured during GetCauseData()");
return Json(new { error = ex.Message.ToString() });
}
}
How do I properly populate the manager select for each form?
I found out the answer to be that I need to create an instance of the dropdown when I create the model data. So for each instance of Model.Projects; each project I defined the full dropdown alongside the selected value.
I use Razor to then define the dropdown as such:
<select class="form-select" asp-for="#project.Manager" asp-items="#project.ManagerList"></select>

Angular - $scope.myForm.$setPristine() is undefined

Form is not cleared after saved record in angularJs. I'm trying to reset form many ways, but form is not reset.
My angularjs version is 1.4.8.
This question is also a duplicate, but I tried what stack overflow users said. That has not worked for me.
Looking for a positive reply
Thank you.
Html code:
<form name="myForm" id="myForm" novalidate>
<input type="hidden" name="forumValue" ng-model="fid.forumValue"
id="forumValue" placeholder="fourm Id" />
<div class="form-group row">
<label for="inputAnswer" class="col-sm-2 col-form-label">Answer</label>
<div class="col-sm-10">
<textarea rows="10" name="answer" class="form-control"
ng-model="fid.answer" required></textarea>
</div>
</div>
<div class="form-group row">
<div class="col-sm-2"></div>
<div class="col-sm-8">
<button type="button" class="btn btn-success"
ng-click="saveUserAnswer(fid)">Post Your Answer</button>
</div>
</div>
</form>
Controller Code:
$scope.saveUserAnswer = function(fid) {
UserRepository.saveUserAnswer(fid).then(
function(response) {
var status = response.message;
if (status == "success") {
alert("posted success");
$scope.UserAnswer=getUserOnIdAnswer(fid.UserValue);
$scope.myForm.$setPristine();
$scope.myForm.$setUntouched();
$state.go('UserAnswer');
}
else {
$scope.User=response;
alert("posted Fail,Please correct the details..!!");
}
});
};
Is your form wrapped in an ng-if statement? If so, the form might be inside a child scope, and you might try:
Option A
Replace your ng-if with an ng-hide.
Option B
Bind the form to an existing object on the parent scope:
$scope.myData = {};
$scope.saveUserAnswer = function(fid) {
...
};
Then in your HTML, refer to the form on the parent scope:
<form name="myData.myForm" id="myForm" novalidate>
</form>
Source: https://github.com/angular/angular.js/issues/15615
I have attempted to recreate your problem but without the call to the UserRepository just to confirm that we can set the form $pristine value to true and to reset the form.
<form name="form.myForm" id="myForm" novalidate>
<input type="hidden" name="forumValue" ng-model="fid.forumValue" id="forumValue" placeholder="fourm Id" />
<div class="form-grou`enter code here`p row">
<label for="inputAnswer" class="col-sm-2 col-form-label">Answer</label>
<div class="col-sm-10">
<textarea rows="10" name="form.myForm.answer" class="form-control" ng-model="fid.answer" required></textarea>
</div>
</div>
<div class="form-group row">
<div class="col-sm-2"></div>
<div class="col-sm-8">
<button type="button" class="btn btn-success" ng-click="saveUserAnswer(fid)">Post Your Answer</button>
</div>
</div>
</form>
<pre>{{form.myForm.$pristine}}</pre>
and the controller code like so :
$scope.form = {};
$scope.saveUserAnswer = function(fid) {
$scope.form.myForm.$setPristine();
$scope.fid = {};
//omitted the user repository code
};
The above will set the pristine value of the form to true and also reset the value of fid on click of the button.
EDIT
Also the call to your repository function should be in this format:
UserRepository.saveUserAnswer(fid).then(
function(response){
//success
},
function(response){
//error
}
);
In controller try to add '$scope.fid.answer=null;' after scope.myForm.$setPristine();
like this.
$scope.saveUserAnswer = function(fid) {
UserRepository.saveUserAnswer(fid).then(
function(response) {
var status = response.message;
if (status == "success") {
alert("posted success");
$scope.UserAnswer=getUserOnIdAnswer(fid.UserValue);
$scope.myForm.$setPristine();
$scope.myForm.$setUntouched();
$scope.fid.answer=null;
$state.go('UserAnswer');
}
else {
$scope.User=response;
alert("posted Fail,Please correct the details..!!");
}
});
};

Writing custom form controls to use v-model in Vue.js

I'm trying to write a custom form control in Vue.js to learn how to package together multiple form inputs into a single custom component.
My project setup looks like this (standard webpack-simple vue cli setup):
$ tree -L 1
.
├── README.md
├── index.html
├── node_modules
├── package.json
├── src
└── webpack.config.js
Here's my top level Vue instance .vue file:
// App.vue
<template>
<div class="container">
<form v-if="!submitted" >
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
<form>
<fullname v-model="user.fullName"></fullname>
<div class="form-group">
<label for="email">Email:</label>
<input id="email" type="email" class="form-control" v-model="user.email">
<label for="password">Password:</label>
<input id="password" type="password" class="form-control" v-model="user.password">
</div>
<fieldset class="form-group">
<legend>Store data?</legend>
<div class="form-check">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="storeDataRadios" id="storeDataRadios1" value="true" checked v-model="user.storeData">
Store Data
</label>
</div>
<div class="form-check">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="storeDataRadios" id="storeDataRadios2" value="false" v-model="user.storeData">
No, do not make my data easily accessible
</label>
</div>
</fieldset>
</form>
<button class="btn btn-primary" #click.prevent="submitForm()">Submit</button>
</div>
</div>
</form>
<hr>
<div v-if="submitted" class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
<div class="panel panel-default">
<div class="panel-heading">
<h4>Your Data</h4>
</div>
<div class="panel-body">
<p>Full Name: {{ user.fullName }}</p>
<p>Mail: {{ user.email }}</p>
<p>Password: {{ user.password }} </p>
<p>Store in Database?: {{ user.storeData }}</p>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import FullName from './FullName.vue';
export default {
data() {
return {
user: {
fullName: 'John Smith',
email: '',
password: '',
storeData: true,
},
submitted: false
}
},
methods: {
submitForm() {
this.submitted = true;
},
},
components: {
'fullname' : FullName,
}
}
</script>
<style>
</style>
And here's the custom component file:
<template>
<div class="form-group">
<label for="firstName">First name:</label>
<input id="firstName" type="text" class="form-control" :value="first" #input="emitChange(true, $event)">
<label for="lastName">Last name:</label>
<input id="lastName" type="text" class="form-control" :value="last" #input="emitChange(false, $event)">
</div>
</template>
<script>
export default {
props: ['value'],
methods: {
emitChange(isFirst, evt) {
let name = '';
let evtValue = evt.target.value == undefined ? "" : evt.target.value;
if (isFirst) {
name = evtValue +" "+ this.second;
} else {
name = this.first +" "+ evtValue;
}
this.value = name;
this.$emit('input', this.value);
}
},
computed: {
first() {
if (this.value != "")
return this.value.split(" ")[0];
else return "";
},
last() {
if (this.value != "")
return this.value.split(" ")[1];
else return "";
}
}
}
</script>
Which I also realize I'm messing up because I'm directly editing a prop value with:
this.value = name;
(not an error, but Vue.JS gives a warning).
However, even before that, typing in the first input box causes the second input box to update its value to undefined (...wat!?).
Would be grateful for advice on how to properly set up custom form control components! (and why this example isn't working).
I think, the problem here is you never know where the first name ends and where the last name starts. Take Barack Hussein Obama for instance and imagine he's Belgian, his name would be Barack Hussein van Obama. You can't safely assume which part ist first and which part is lastname.
However, if you could say the firstname is exactly one word and the rest is lastname, here's an example implementation (stripped down). To illustrate the problem, try to put in Obamas second name.
Otherwise, the component behaves like a two way bound component. You can alter the separate values on the fullname component, or edit the fullname on the root component and everything stays up to date. The watcher listens for changes from above, the update method emits changes back up.
Vue.component('fullname', {
template: '#fullname',
data() {
// Keep the separate names on the component
return {
firstname: this.value.split(' ')[0],
lastname: this.value.split(' ')[1],
}
},
props: ['value'],
methods: {
update() {
// Notify the parent of a change, chain together the name
// and emit
this.$emit('input', `${this.firstname} ${this.lastname}`);
},
},
mounted() {
// Parse the prop input and take the first word as firstname,
// the rest as lastname.
// The watcher ensures that the component stays up to date
// if the parent changes.
this.$watch('value', function (value){
var splitted = value.split(' ');
this.firstname = splitted[0];
splitted.shift();
this.lastname = splitted.join(' ');
});
}
});
new Vue({
el: '#app',
data: {
fullname: 'Barack Obama',
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
<div id="app">
<fullname v-model="fullname"></fullname>
<p>Thanks, {{fullname}}</p>
<input v-model="fullname" />
</div>
<template id="fullname">
<div>
<input v-model="firstname" #input="update" type="text" id="firstname" />
<input v-model="lastname" #input="update" type="text" id="lastname" />
</div>
</template>

How to execute an action when textbox's content has changed?

I have two actions like:
Function getNews: to get list news.
Function searchNews: to get list news base on a keyword.
I create a form to submit that:
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<form id="getNew" action="<?php echo admin_url('Xpathnews/searchKeyword') ?>" method="post">
<div class="col-md-12 col-sm-12 col-xs-12">
<h4><b>Select your news</b></h4>
<select id="selectcate" name="selectcate" class="field-custom">
<option value="http://theverge.com">The Verge</option>
<option value="http://neowin.net">Neowin</option>
</select>
</div>
<div class="col-md-12 col-sm-12 col-xs-12">
<h4><b>Keyword:</b></h4>
<input name="search_keyword" id="search_keyword" autocomplete="off" placeholder="Enter your keyword..." />
</div>
<div class="col-md-12 col-sm-12 col-xs-12">
<input name="xpath_title" id="xpath_title" type="hidden" />
</div>
<br>
<div class="col-md-12 col-sm-12 col-xs-12 text-center">
<input name="get_news" type="submit" id="get_news" value="Get News"/>
</div>
</form>
Or fiddle link: https://jsfiddle.net/f7zy0694/2/
I want when the user types any text in textbox search_keyword. Will execute action searchNews.
Usually, the user only clicks button Get News default execute action getNews.
I tried a solution in my controller/action:
public function getNews(){
$xpath_title = $this->input->post('xpath_title');
}
public function searchNews() {
$keyword = $this->input->post('search_keyword');
if(empty($keyword)) {
$this->getNews();
} else {
// execute my code at here
}
}
... is check if $keyword don't have value it will execute function $this->getNews but problem is:
I have some <input> hidden, seem the call to function getNews it not working.
I also tried with seft:redirect("/getNews").
Thanks.
In that you can use Jquery ajax with keyUp or keyDown like:
$(document).ready(function(){
$('#searchbox_id').keyUp(function(){
// get the user entered string
var searchTxt = $(this).val();
$.ajax({
url: 'process_file.php',
type: 'get',
data: {
searchTxt :searchTxt
},
success: function(response){
// do your stuff here
}
});
});
});

AngularJS reset form completely

I have a pretty big form that's being validated on the client side by Angular. I am trying to figure out how to reset the state of the form and its inputs just clicking on a Reset button.
I have tried $setPristine() on the form but it didn't really work, meaning that it doesn't clear the ng-* classes to reset the form to its original state with no validation performed.
Here's a short version of my form:
<form id="create" name="create" ng-submit="submitCreateForm()" class="form-horizontal" novalidate>
<div class="form-group">
<label for="name" class="col-md-3 control-label">Name</label>
<div class="col-md-9">
<input required type="text" ng-model="project.name" name="name" class="form-control">
<div ng-show="create.$submitted || create.name.$touched">
<span class="help-block" ng-show="create.name.$error.required">Name is required</span>
</div>
</div>
</div>
<div class="form-group">
<label for="lastName" class="col-md-3 control-label">Last name</label>
<div class="col-md-9">
<input required type="text" ng-model="project.lastName" name="lastName" class="form-control">
<div ng-show="create.$submitted || create.lastName.$touched">
<span class="help-block" ng-show="create.lastName.$error.required">Last name is required</span>
</div>
</div>
</div>
<button type="button" class="btn btn-default" ng-click="resetProject()">Reset</button>
</form>
And my reset function:
$scope.resetProject = function() {
$scope.project = {
state: "finished",
topic: "Home automation"
};
$("#create input[type='email']").val('');
$("#create input[type='date']").val('');
$scope.selectedState = $scope.project.state;
// $scope.create.$setPristine(); // doesn't work
}
Also if you could help me clear the input values of the email and date fields without using jQuery would be great. Because setting the $scope.project to what's defined above doesn't reset the fields for some reason.
Try to clear via ng-model
$scope.resetProject = function() {
$scope.project = {
state: "finished",
topic: "Home automation"
};
$("#create input[type='email']").val('');
$("#create input[type='date']").val('');
$scope.selectedState = $scope.project.state;
$scope.project = {
name: "",
lastName: ""
};
}
As mentioned in the comments, you can use $setUntouched();
https://docs.angularjs.org/api/ng/type/form.FormController#$setUntouched
This should set the form back to it's new state.
So in this case $scope.create.$setUntouched(); should do the trick
Ref all that jquery. You should never interact with the DOM via controllers. That's what the directives are for
If you want to reset a given property then do something like:
$scope.resetProject = function() {
$scope.project = {
state: "finished",
topic: "Home automation"
};
$scope.project.lastName = '';
$scope.project.date= '';
}

Categories