I have two fields in the exported class. The template has a drop-down with its ngModel bound to the first field (selectedInterval) with two-way binding. When the dropdown option changes, the calculateReviewDate() event takes place and successfully updates the 2nd field (nextReviewDate), but the dropdown stays blank until I select the same option twice. In addition, the spinner never appears during the calculation. Does anyone know why?
<form #FormVar="ngForm" novalidate>
<div class="form-group">
<div class="row">
<div class="col col-md-2 col-sm-3">
<input type="text" [ngModel]="nextReviewDate | date:shortDate" name="nextReviewDate" id="nextReviewDate1" class="form-control" disabled/>
</div>
<div class="col col-md-1 com-sm-3" *ngIf="showSpinner">
<fa [name]="'spinner'" [size]=1 [spin]=true></fa>
</div>
<div class="col col-md-2 col-sm-3">
<select class="form-control" name="nextReviewDate" id="nextReviewDate2" [(ngModel)]="selectedInterval" (change)="calculateReviewDate()">
<option *ngFor="let r of reviewIntervals" [value]="r.interval">{{r.intervalDescription}}</option>
</select>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary" [disabled]="!FormVar.valid" (click)="save(FormVar)">Review Note</button>
</form>
calculateReviewDate(): void {
this.showSpinner = true;
let calculator: calculateDate = new calculateDate();
let today: Date = new Date();
this.nextReviewDate = calculator.addMonth(today, this.selectedInterval);
this.showSpinner = this.nextReviewDate === undefined;
}
How you get reviewIntervals? And for the spinner, my thought it's because too fast, try to add a delay before this.showSpinner = this.nextReviewDate === undefined;like set time out.
Not sure about your issue with the select, but I know what is going on with your spinner. You have no asychronous code in your calculateReviewDate method so the spinner won't be shown. JS runs on a single thread and unless you break the synchronous code up into parts that allow the control to be given back to the browser to paint, your spinner will not be shown.
I think you have two issues here:
1. onChange, the selected value is not shown the first time.
2. Spinner is not shown on Select value change.
Why the Spinner is not shown?
On Change since the calculateReviewDate() method is being called directly (Synchronous behavior), and in this method the spinner is set to true in the starting and then state gets set to either true/false based on nextReviewDate variable, I guess nextReviewDate variable would never become undefined,so nextReviewDate always holds some valid value, so it sets to false again, so in the background the spinner will become rendered and immediately gets removed as you have used a structural directive and all logic in the method happens synchronous manner and will be in a very short span, so visually we are not able to see the rendered spinner getting on and off.
Why the Select controls selected value is not shown?
I have shared a modified example of your version in which things are fine,
Template:
<div>
<form #FormVar="ngForm" novalidate>
<div class="form-group">
<div class="row">
<div class="col col-md-2 col-sm-3">
<div class="form-group">
<input type="text" [ngModel]="nextReviewDate" name="nextReviewDate" id="nextReviewDate1" class="form-control" disabled/>
</div>
</div>
<div class="col col-md-1 com-sm-3" *ngIf="showSpinner">
<p>Spinner</p>
</div>
<div class="col col-md-2 col-sm-3">
<select class="form-control" name="nextReviewDate" id="nextReviewDate2" [(ngModel)]="selectedInterval" (change)="calculateReviewDate()">
<option *ngFor="let r of reviewIntervals" [value]="r">{{r}}</option>
</select>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary" >Review Note</button>
</form>
</div>
TS:
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
reviewIntervals = [1,2,3,4,5];
selectedInterval = 5;
showSpinner = false;
nextReviewDate;
calculateReviewDate(value): void {
this.nextReviewDate = this.selectedI`enter code here`nterval;
}
}
Related
I have my chat and I dont want people to send empty message so I would like that my input become required. Thanks for your help.
I tried to put "required='required'" in the input line, I also tried veeValidate but it broke my chat when I use it, I also tried to put "Required = true" in Props and data but without a good result
This is ChatForm.vue
<template>
<div class="input-group" >
<input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="Ecrire..." v-model="newMessage" #keyup.enter="sendMessage">
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendMessage">
✓
</button>
</span>
</div>
</template>
<script>
export default {
props: ['user'],
data() {
return {
newMessage: '',
}
},
methods: {
sendMessage() {
this.$emit('messagesent', {
user: this.user,
message: this.newMessage
});
setTimeout(function() {
const messages = document.getElementById('mess_cont');
messages.scrollTop = messages.scrollHeight;
}, 200);
this.newMessage = '';
}
}
}
</script>
And this is my form in the app.blade.php
<div id="app" class="container-chat">
<div class="row">
<div class="col-md-12 col-md-offset-2">
<div class="col-md-12 col-md-offset-2">
<div class="panel-body panel-content" id="mess_cont">
<chat-messages id="mess" :messages="messages" :currentuserid="{{Auth::user()->id}}"></chat-messages>
</div>
<div class="panel-footer">
<chat-form
v-on:messagesent="addMessage"
:user="{{ Auth::user() }}"
></chat-form>
</div>
</div>
</div>
</div>
</div>
Try to change your ChatForm.vue like this:
<template>
<form #submit.prevent="sendMessage">
<div class="input-group" >
<input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="Ecrire..." v-model="newMessage" required>
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" type="submit" id="btn-chat">
✓
</button>
</span>
</div>
</template>
You are not treating the input in the correct way, the input which is required needs to be inside a form and the required keyword will prevent the form submission if the input field is empty.
There are a few things I would do differently.
1/ Wrap your chat form in a tag, and execute the sendMessage() method on submit. This will give your users a nicer experience, as they can just to submit the message.
2/ Convert the button into a submit button so it triggers the form.submit event.
3/ You can easily disable the button by checking whether newMessage has contents. I don't think you need vee validate or anything else to achieve this; for something as simple as a chat form, your user doesn't need much more feedback than seeing a disabled button to realise (s)he needs to write something first.
4/ in the addMessage method you can just check the contents of newMessage and not do anything when it's empty. This is perfectly fine because you already hinted the user by disabling the button too.
I think this is a subtle way where you guide your user, but don't overdo it.
Please add name attributes to all of your form elements. Some of the element in my form had name attribute and some didn't. Element which had name attributes worked correctly but the one's which didn't had name failed.
I have a form where the user can input multiple addresses, city, street+nbr and country.
For this field to be repeated I use the jquery repeater library. For the city field I want to use a selectize input field.
I am trying to repeat those 4 fields when clicking on the button, it copies everything correctly but the selectize field does not contain inputs (i guess this is because they have the same id?) but I don't know how to instantiate another selectize instance on that object.
This is my code:
HTML:
<div class="row">
<div class="form-group col-12 mb-2 address-repeater">
<div data-repeater-list="stcity">
<div class="input-group mb-1" data-repeater-item>
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label for="companystreet"><?=lang("flow_company_street")?></label>
<input type="text" id="companystreet" class="form-control" placeholder="<?=lang("flow_company_streetname")?>" name="companystreet" required data-validation-required-message="<?=lang("flow_company_street_validation")?>">
<div class="help-block font-small-3"></div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="companystreetnumber"><?=lang("flow_company_nbr")?></label>
<input type="text" id="companystreetnumber" class="form-control" placeholder="<?=lang("flow_company_streetnbr")?>" name="companystreetnumber" required data-validation-required-message="<?=lang("flow_company_nbr_validation")?>">
<div class="help-block font-small-3"></div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="companycity"><?=lang("flow_company_city_or_commune")?></label>
<select id="companycity" class="companycity-select" name="companycity" autocomplete="new-password" required data-validation-required-message="<?=lang("flow_company_city_or_commune_validation")?>">
<option value="" selected><?=lang("flow_company_select_city_or_commune")?></option>
<?php
foreach ($citiesbe as $city) {
//Values are prefilled from javascript
$key = strtolower($city->name_nl) . "," . $city->zip_code;
echo "<option value=\"$key\"> $city->name_nl ($city->zip_code)</option>";
}
?>
</select>
<div class="help-block font-small-3"></div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="companycountry"><?=lang("flow_company_country")?></label>
<select id="companycountry" class="companycountry-select" name="companycountry" autocomplete="new-password" disabled>
<option value="BE" selected><?=lang("flow_company_country_belgium")?></option>
</select>
</div>
</div>
</div>
</div>
</div>
<button type="button" data-repeater-create class="btn btn-primary">
<i class="ft-plus"></i> Add new address
</button>
</div>
Javascript:
// Custom Show / Hide Configurations
$('.address-repeater').repeater({
show: function () {
$(this).slideDown();
},
hide: function(remove) {
$(this).slideUp(remove);
}
});
Since the button is not the selectize element, I don't know how to assign it to the newly created element.
Funny, I ran into a similar problem, but couldn't find a solution, so I had to work it out myself. Here's an explanation to the solution I applied to get selectize and jquery.repeater to work nicely.
First, checking through the browser console, you'll find out that selectize removes all the select options except the empty option, and uses it to populate it's own dropdown which is generated via javascript. This becomes a problem for jquery.repeater because it only repeats or creates a duplicate based on the initial page load, and not after. So, what gets repeated is the only select option left in the select element, which in this case (unfortunately) is the empty select option. Here's a pen explaining this, feel free to toggle the category targeting selectize in the select element to see for yourself.
So, here are the steps I took to get it to work nicely:
On repeating of the form (show() of the repeater instance), you'll need to delete the duplicated element completely from the DOM.
Create another select element(s) in the DOM with the preferred (or same) attributes/options.
Instantiate selectize on the newly created select element(s).
I'll suggest you add a class to the .form-group wrapper housing the .companycity-select select element. This will help to append a new select element at the exact place only, since there are other .form-group in the code. Check my solution below:
// Assuming your have the select element wrapper as <div class="form-group select-wrapper">
$('.address-repeater').reapeter({
show: function() {
$(this).slideDown();
// Remove the created element
$(this).find('.companycity-select').remove();
// Repeater rewrites your name attributes to avoid collisions within the same form,
// so we need to follow this same rule
// Get the length of the currently repeated items, to be used as the index for new elements
var count = $('div[data-repeater-item]').length;
// Create the new select element. The select name is based on the new name by repeater
var new_select_option = '<option value="" selected>Select city or community</option>';
var new_select_element = '<select id="companycity" class="companycity-select" name="stcity['+count+'][companycity]" autocomplete="new-password" required>'+new_select_option+'</select>';
// Append newly created element to DOM. Remember the new class added to the form-group?
$(this).find('.form-group.select-wrapper').append(new_select_element);
// Create a new instance of selectize on the new select element
$(this).find('.companycity-select').selectize({
// Populate your select options data via ajax,
// see docs: https://selectize.dev/docs.html
valueField: '',
labelField: '',
searchField: [],
options: []
});
}
});
I need your help. I am trying to realize a live search. So whenever I switch from one TextBox to another, a form should be submitted, to update the URL and to pass the data to the controller. It works perfectly fine when I click the submit button but it does not work the way I want.
Here is my code:
Controller:
public ActionResult Index(string number, string caption)
{
//Fetch data from the database
return View();
}
View:
$(document).ready(function () {
$('#number').change(function () {
$('#filter').submit();
});
});
#using (Html.BeginForm("Index", "Home", FormMethod.Get, new { id = "filter" }))
{
<div class="row">
<div class="col-sm-2 checkbox">
Number:
</div>
<div class="col-sm-3">
#Html.TextBox("Number", "", new { #class = "form-control", type = "text", id = "number" })
</div>
</div>
<div class="row">
<div class="col-sm-2 checkbox">
Caption:
</div>
<div class="col-sm-3">
#Html.TextBox("Caption", "", new { #class = "form-control", type = "text", id = "caption" })
</div>
</div>
<div class="row">
<div class="col-sm-2 col-sm-offset-2">
<button type="submit" id="submit" class=" btn btn-block btn-primary">Search</button>
</div>
</div>
}
Output HTML:
<script>
$(document).ready(function () {
$('#number').change(function () {
$('#filter').submit();
});
});
</script>
<form action="/" id="filter" method="get"> <div class="row">
<div class="col-sm-2 checkbox">
Number:
</div>
<div class="col-sm-3">
<input class="form-control" id="number" name="Number" type="text" value="">
</div>
</div>
<div class="row">
<div class="col-sm-2 checkbox">
Caption:
</div>
<div class="col-sm-3">
<input class="form-control" id="caption" name="Caption" type="text" value="">
</div>
</div>
<div class="row">
<div class="col-sm-2 col-sm-offset-2">
<button type="submit" id="submit" class=" btn btn-block btn-primary">Search</button>
</div>
</div>
Browser Console:
Uncaught TypeError: elem[type] is not a function
at Object.trigger (http://localhost:49782/Scripts/jquery-1.8.2.js:2991:18)
at HTMLFormElement.<anonymous> (http://localhost:49782/Scripts/jquery-1.8.2.js:3618:17)
at Function.each (http://localhost:49782/Scripts/jquery-1.8.2.js:625:20)
at init.each (http://localhost:49782/Scripts/jquery-1.8.2.js:255:17)
at init.trigger (http://localhost:49782/Scripts/jquery-1.8.2.js:3617:15)
at init.jQuery.fn.(anonymous function) [as submit] (http://localhost:49782/Scripts/jquery-1.8.2.js:3671:9)
at HTMLInputElement.<anonymous> (http://localhost:49782/:63:26)
at HTMLInputElement.dispatch (http://localhost:49782/Scripts/jquery-1.8.2.js:3077:9)
at HTMLInputElement.eventHandle (http://localhost:49782/Scripts/jquery-1.8.2.js:2695:28)
Your JavaScript code is looking for the tag with ID #number. Because browsers mostly read the source code from the top to the bottom, the code will be evaluated well before the #number <input> is even declared. This means that jQuery will not find it and will therefore not attach the event. If you move the script after the HTML, or wrap it into document.ready, it will work as expected:
$(document).ready( function() {
$('#number').change(function () {
$('#filter').submit();
});
} );
//or simpler equivalent
$( function () { ... } );
This however will still not work as you want, because each time the input changes, the whole page will be posted back to the server, so user will have to wait for the entire page to reload after he tries to switch focus from one input to another. This is not very convenient and you would probably be better off changing the logic to use AJAX calls and dynamically update the search results. Although it is not a requirement, it is a nice to have and user-friendly approach :-) .
Update - solution to submit error
I have just found the solution for the error you get trying to submit. Your submit button's id is submit. This is not "wrong" per se, but it causes a problem trying to submit with jQuery. You see, because the button is inside your form, when jQuery returns the #filter form, when you try to use submit() on it, JavaScript finds your submit button in scope and thinks that you want to "call it" - hence you get the error, because you you cannot "call" an element. This might also happen if you use submit as the name of a button.
The best and easiest solution for you will be to change the id to something else:
<button type="submit" id="submitButton" class=" btn btn-block btn-primary">Search</button>
In modern browsers use the input event. This event will fire when the user is typing into a text field, pasting, undoing, basically anytime the value changed from one value to another.
$('#number').on('input', function() {
$('#filter').submit();
});
It's working fine for me I hope it also working for u
C# Code:
[HttpPost]
public ActionResult Index(string firstname)
{
return Json("Done");
}
Razor Code
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
var abc = document.getElementById('Number');
abc.onchange = (function () {
document.forms[0].submit();
});
});
</script>
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id= "filter" }))
{
<div class="row">
<div class="col-sm-2 checkbox">
Number:
</div>
<div class="col-sm-3">
#Html.TextBox("Number", "", new { #class = "form-control", type = "text", id = "Number" })
</div>
</div>
<div class="row">
<div class="col-sm-2 checkbox">
Caption:
</div>
<div class="col-sm-3">
#Html.TextBox("Caption", "", new { #class = "form-control", type = "text", id = "caption" })
</div>
</div>
<div class="row">
<div class="col-sm-2 col-sm-offset-2">
<button type="submit" id="submit1" class=" btn btn-block btn-primary">Search</button>
</div>
</div>
}
Do Not use submit as id or name of button it override the meaning of Java Script submit Method
I use Angular2, and have html code
<div class="row">
<div class="col-xs-3 form-group">
<select class="form-control"
id="country"
[(ngModel)]="testSelectModel"
(change)="testSelectChange($event)">
<option *ngFor="let item of textCollection"
[value]="item.id">
{{item.name}}
</option>
</select>
</div>
<div class="col-xs-3 form-group">
<input type="text"
class="form-control"
[(ngModel)]="testSelectModel"/>
</div>
</div>
I also have a collection of textCollection, objects which - {
name: 'foo',
id: 1
}...
I enter (id) in input 1, and wanted see selected item in tag select.
Yes, all is well, the item has changed, but the event "testSelectChange" - is not invoked..
example
Somebody faced such?
If you modify the input, testSelectChange() won't get called, even though the select DOM element and the input DOM element are both bound to the same component property, testSelectModel. Angular will only call testSelectChanges() if there is a change to one of select's DOM properties, and this doesn't happen when you change the input value.
I suggest breaking up the event and data binding – use [ngModel] and (ngModelChange) – for each binding:
<select [ngModel]="testSelectModel"
(ngModelChange)="testSelectChange($event)">
...
<input [ngModel]="testSelectModel"
(ngModelChange)="testInputChange($event)">
Note that $event will be set to the current value of the select or input.
Then manually call the the select change event handler from testInputChange():
testSelectChange(newValue) {
console.log('testSelectChange', newValue);
this.testSelectModel = newValue;
this.resultWorkModel = newValue;
}
testInputChange(newValue) {
console.log('testInputChange', newValue)
this.testSelectModel = newValue;
this.testSelectChange(newValue); // manually trigger other event handler
}
Plunker
Besides what the other commenters have said, you might also need to write your handler in a Future, because the changes to testSelectModel might not have taken effect before testSelectChange($event) has happened.
This was the case in Angular1.
This should work:
Plunker Code
html:
<select class="form-control" #type [(ngModel)]="testSelectModel" (change)='testSelectChange(type.value)'>
<option *ngFor="#item of textCollection" [value]="item.id">
{{item.name}}
</option>
</select>
class:
testSelectChange(val: string) {
console.log('I call', val);
this.resultWorkModel = this.textCollection.find((obj) => obj.id == val).name;
}
The event for handle changes in the model is ngModelChange, your code should be like this:
<div class="row">
<div class="col-xs-3 form-group">
<select class="form-control"
id="country"
[(ngModel)]="testSelectModel"
(ngModelChange)="testSelectChange($event)">
<option *ngFor="let item of textCollection"
[value]="item.id">
{{item.name}}
</option>
</select>
</div>
<div class="col-xs-3 form-group">
<input type="text"
class="form-control"
[(ngModel)]="testSelectModel"/>
</div>
</div>
This is a example in Plunker Enjoy.
I'm pulling the variables from a database and the values could either be Manual or Automatic. Users can also use a dropdown to change the values.
If the value is already Manual I need it to unhide a DIV or if it was Automatic and the user switches to Manual I need to unhide a DIV.
What I have currently only unhides if it was Automatic and user selects Manual.
Here is a JSFiddle: http://jsfiddle.net/DTcHh/5031/
Any help would be appreciated.
Thanks!
HTML:
<form class="form-horizontal" method="post">
<div class="form-group">
<label class="col-md-5 control-label" for="method">Method:</label>
<div class="col-md-6">
<select id="method" name="method" class="form-control">
<option value="Automatic">Automatic</option>
<option value="Manual">Manual</option>
</select>
</div>
</div>
<div id="manual" class="panel panel-default" style="display:none">
<div class="panel-heading">
<h4 class="panel-title">
Manual
</h4>
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-5 control-label" for="activitycomplete">Activity Complete:</label>
<div class="col-md-6">
<select id="activitycomplete" name="activitycomplete" class="form-control">
<option value="False">False</option>
<option value="True">True</option>
</select>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<div class="form-actions">
<button type="submit" class="btn btn-success">Update</button>
<button type="button" data-dismiss="modal" class="btn btn-default">Back</button>
</div>
</form>
JQuery:
$(document).ready(function () {
$('#method').change(function () {
$('#manual').toggle(500);
});
//$("#method").val('Manual');
});
There's no logic in the code which actually checks the value. Basically, this rule isn't implemented:
If the value is already Manual I need it to unhide a DIV or if it was Automatic and the user switches to Manual I need to unhide a DIV.
The code is assuming that the initial value is always "Automatic" and that there will always ever be a one-way-or-the-other switch between the two values. This assumption is incorrect.
Instead of assuming the value and just toggling, explicitly show/hide based on the inspected value:
$('#method').change(function () {
if ($(this).val() == 'Manual') {
$('#manual').show(500);
} else {
$('#manual').hide(500);
}
});
Which you can extract into a function so it can be invoked manually as well:
var toggleDiv = function () {
if ($('#method').val() == 'Manual') {
$('#manual').show(500);
} else {
$('#manual').hide(500);
}
}
$('#method').change(toggleDiv);
Then you can invoke it when the page first loads as well:
$("#method").val('Manual');
toggleDiv();
Example here.
You'll want to check the value of the dropdox and on page load if it is manual run the toggle function:
$(document).ready(function () {
$('#method').change(function () {
$('#manual').toggle(500);
});
var valueOfDropDown = $('#method').val();
if(valueOfDropDown === "Manual"){
$('#manual').toggle(500);
}
});
This will obviously show the box on once the dom is ready.