I am initializing select2(multiple) with remote data (json) and when the form is submitted select2 submits the indexes of the selected text(s), can it return selected text(in comma separated like indexes) instead of indexes?
<input type="hidden" id="IntendedCourses" name="IntendedCourses"/>
$.getJSON("GetCourses.aspx", function (course) {
$("#IntendedCourses").select2({
multiple: true,
data: course
});
});
json format :
[{"id":"0","text":"Accounting"},{"id":"1","text":"Accounting & Finance"},{"id":"2","text":"Aeronautical"},{"id":"3","text":"Aerospace Engineering"}]
I believe what you need is:
$("#IntendedCourses").change(function() {
var selection = (JSON.Stringify($("#IntendedCourses").select2('data')));
});
This should give you the JSON for what is inside the selection upon change.
Related
I have two entities - Budget and Income. On the "view budget" page I have this hyperlink, from where the user can create an income to that specific budget:
Create income to this budget
// Result: /income/new?budget=1
// What I want: /income/new
Is it possible somehow to remove ?budget=1 and still pass on the budget.id as a POST variable value so the hyperlink becomes short: /income/new?
You cant pass post parameters with an anchor
You could use a form though, sth like:
<form action="{{ path('app_income_new') }}" method="POST">
<input type="hidden" name="budget" value="{{ budget.id }}">
<input type="submit" value="Create income to this budget">
</form>
should do the trick, maybe add some css to make it "look like a link"
In order to have this behavior with just an actual anchor <a> element you need to use a javascript event listener to build and submit a form element when the anchor is clicked. You can insert the related data (path & budget.id) into data attributes of the anchor. The event listener can access the data of the clicked anchor (so you can have many with different datasets). Below is a configurable example that can support additional fields by adding the field name where noted, and the appropriate data attribute.
const postAnchors = document.querySelectorAll(".post-link");
postAnchors.forEach((anchor) => {
anchor.addEventListener('click', function(e) {
const fields = [
'budget',
// to support additional fields add here
]
const form = document.createElement('form')
fields.forEach(field => {
if (anchor.dataset[field]) {
const input = document.createElement('input')
input.name = field
input.type = 'text'
input.value = anchor.dataset[field] // data-{field} value
form.append(input)
}
})
form.method = 'post'
form.action = anchor.dataset.action
document.querySelector('body').append(form)
form.submit()
})
})
Create income to this budget
I am getting this error when I try to build a reactive form for creating a new password form.I have mentioned the source code below and when I remove the source code part then there is no error but without that my operation is not working as well. I think I have to add or delete something in my source code to get the desired output
main.ts:12 TypeError: Cannot read property 'value' of null
at FormGroup.passwordShouldMatch [as validator] (password.validators.ts:18)
at FormGroup._runValidator (forms.js:4089)
at FormGroup.updateValueAndValidity (forms.js:4050)
at new FormGroup (forms.js:4927)
at FormBuilder.group (forms.js:8924)
at new ChangePasswordComponent (change-password.component.ts:15)
at createClass (core.js:31987)
at createDirectiveInstance (core.js:31807)
at createViewNodes (core.js:44210)
at callViewAction (core.js:44660)
static passwordShouldMatch(control : AbstractControl) {
let newPassword = control.get('newPassowrd');
let confirmPassword = control.get('confirmPassowrd');
if (newPassword.value !== confirmPassword.value){
return { passwordShouldMatch:true };
return null;
}
}
As you didn't add any code snippet I am considering your form structure is something like this.
this.fb.group({
newPassowrd: [''],
confirmPassowrd: [''],
});
here, you include an custom validation function called passwordShouldMatch and this function looks fine. So, I assume that you did something wrong when you set the validator to that form group.
this.fb.group({
newPassowrd: [''],
confirmPassowrd: [''],
}, { validator: this.passwordShouldMatch});
this is how you should set the validation function for the form group. And in html your form should be something like this.
<form [formGroup]="form" novalidate (ngSubmit)="onSubmit(survey)">
<input type="text" placeholder="Untitled form" formControlName="newPassowrd">
<input type="text" placeholder="Untitled form" formControlName="confirmPassowrd">
<span *ngIf="form.hasError('passwordShouldMatch')">not match</span>
</form>
everything should work this way. Here is the working version of stackblitz
I'm using Meteor with React. I have a really simple goal, but i have tried a lot and can't solve it for myself. I will show you my attemps below.
I want to create a form for the Ingredients. At the first moment there is only one input (for only one ingredient) and 2 buttons: Add Ingredient and Submit.
class IngredientForm extends Component {
render() {
return(
<form onSubmit={this.handleSubmit.bind(this)}>
<input type="text"/>
{ this.renderOtherInputs() }
<input type="button" value="Add Ingredient" onClick={this.addIngredient.bind(this)}>
<input type="submit" value="Submit Form">
</form>
);
}
}
So when I click Submit then all the data goes to the collection. When I click Add Ingredient then the another text input appears (in the place where renderOtherInputs() ).
I know, that Meteor is reactive - so no need to render something directly. I should underlie on the reactive data storage.
And I know from the tutorials the only one way to render something - I should have an array (that was based on collection, which is always reactive) and then render something for each element of that array.
So I should have an array with number of elements = number of additional inputs. that is local, so I can't use Collection, let's use Reactive Var instead of it.
numOfIngredients = new ReactiveVar([]);
And when I click Add button - the new element should be pushed to this array:
addIngredient(e) {
e.preventDefault();
let newNumOfIngredients = numOfIngredients.get();
newNumOfIngredients.push('lalal');
numOfIngredients.set(newNumOfIngredients);
}
And after all I should render additional inputs (on the assumption of how many elements I have in the array):
renderOtherInputs() {
return numOfIngredients.get().map((elem) => {
return(
<input type="text"/>
);
}
}
The idea is: when I click Add button then new element is pushed to the ReactiveVar (newNumOfIngredients). In the html code I call this.renderOtherInputs(), which return html for the as many inputs as elements I have in my ReactiveVar (newNumOfIngredients). newNumOfIngredients is a reactive storage of data - so when I push element to it, all things that depends on it should re-render. I have no idea why that is not working and how to do this.
Thank you for your help.
Finally I got the solution. But why you guys don't help newbie in web? It is really simple question for experienced developers. I read that meteor and especially react have powerful communities, but...
the answer is: we should use state!
first let's define our state object in the constructor of react component:
constructor(props) {
super(props);
this.state = {
inputs: [],
}
}
then we need a function to render inputs underlying our state.inputs:
renderOtherInputs() {
return this.state.inputs.map( (each, index) => {
return (
<input key={ index } type="text" />
);
});
}
and to add an input:
addInput(e) {
e.preventDefault();
var temp = this.state.inputs;
temp.push('no matter');
this.setState({
inputs: temp,
});
}
p.s. and to delete each input:
deleteIngredient(e) {
e.preventDefault();
let index = e.target.getAttribute('id');
let temp = this.state.inputs;
delete temp[index];
this.setState({
inputs: temp,
});
}
In my autoform the value of a field is the difference of two other input fields. It is not allowed to be updated by the user. Unfortuantly at the moment it is not possible to set a single field to readonly in a form. So my approach is to create an autoValue and a custom Validation to prevent an update
My code so far:
'SiteA.Settings.RXSignalODU1difference': {
type: Number,
label: "RX Signal [dBm] ODU1 difference (without ATPC +/- 3dbm)",
decimal: true,
autoform: {
type: "number"
},
autoValue: function() {
var ODU1gemessen = this.field("SiteA.Settings.RXSignalODU1");
var ODU1planned = this.field("SiteA.Settings.RXSignalODU1planned");
if (ODU1gemessen.isSet || ODU1planned.isSet) {
return ODU1gemessen.value - ODU1planned.value;
}
},
custom: function() {
var ODU1gemessen = this.field("SiteA.Settings.RXSignalODU1");
var ODU1planned = this.field("SiteA.Settings.RXSignalODU1planned");
var dif = ODU1gemessen.value - ODU1planned.value;
if (this.value !== dif) {
return "noUpdateAllowed";
}
}
},
My Simple.Schema message:
SimpleSchema.messages({noUpdateAllowed: "Can't be updated"});
Unfortunatly no message pops up.
EDIT
This method will create a disabled input box within your form that will automatically show the difference between two other input fields as the user types.
First, we define session variables for the values used in the calculation and initialize them to undefined.
Template.xyz.onRendered({
Session.set("ODU1gemessen", undefined);
Session.set("ODU1planned", undefined);
});
Then we define two events, that will automatically update these session variables as the user types.
Template.xyz.events({
'keyup #RXSignalODU1' : function (event) {
var value = $(event.target).val();
Session.set("ODU1gemessen", value);
},
'keyup #RXSignalODU1planned' : function (event) {
var value = $(event.target).val();
Session.set("ODU1planned", value);
}
});
Then we define a helper to calculate the difference.
Template.xyz.helpers({
RXSignalODU1difference : function () {
var ODU1gemessen = Session.get("ODU1gemessen");
var ODU1planned = Session.get("ODU1planned");
if (!!ODU1gemessen || !!ODU1planned) {
return ODU1gemessen - ODU1planned;
}
}
});
My HTML markup looks like this. Note, to still control the order of the form, I use a {{#autoform}} with a series of {{> afQuickfields }} rather than using {{> quickForm}}.
To display the calculated difference, I just create a custom div with a disabled text box.
<template name="xyz">
{{#autoForm collection="yourCollection" id="yourId" type="insert"}}
<fieldset>
<legend>Enter legend text</legend>
{{> afQuickField name="SiteA.Settings.RXSignalODU1" id="RXSignalODU1"}}
{{> afQuickField name="SiteA.Settings.RXSignalODU1planned" id="RXSignalODU1planned"}}
<div class="form-group">
<label class="control-label">RXSignalODU1difference</label>
<input class="form-control" type="text" name="RXSignalODU1difference" disabled value="{{RXSignalODU1difference}}">
<span class="help-block"></span>
</div>
</fieldset>
<button class="btn btn-primary" type="submit">Insert</button>
{{/autoForm}}
</template>
Original Answer - not recommended
If you are generating your form as a quickForm, you could do something like
{{>quickForm collection='yourCollection' omitFields='SiteA.Settings.RXSignalODU1difference'}}
This will leave this field off the form, so the user won't be able to update it.
If you still want to display the value somewhere along with the form as the user types in the other two values, you could define a helper in your client side js
something like
Template.yourFormPage.helpers({
diff: function () {
var ODU1gemessen = $('[name=SiteA.Settings.RXSignalODU1]').val();
var ODU1planned = $('[name=SiteA.Settings.RXSignalODU1planned]').val();
if (!!ODU1gemessen || !!ODU1planned) {
return ODU1gemessen - ODU1planned;
}
}
});
You'll want to double check how the field names are being rendered in your DOM. Autoform assigns the name attribute using the field names in your schema, but I don't know how it handles nested keys... (i.e. whether it names the element 'SiteA.Settings.RXSignalODU1' or just 'RXSignalODU1' )
And then just display the value somewhere in your html as :
{{diff}}
I am using bootstrap-daterangepicker in a form. The way I am currently grabbing the value of this selection works but the way I am getting the values doesn't seem like a good way.
It seems bad to use the Session to hold the field selections and then unset them when i am done. I just want to be sure that I am not missing something.
I could get the value from the input field but I would have to parse the string to pull the dates out. Doping this could be a maintenance headache because I would need to change the parsing if I change the daterangepicker date formats.
The form field:
<input type="text" name="carpool_eventDates" id="carpool_eventDates" />
JS to activate the component:
Template.add_event.rendered = function () {
// initialize add event modal;
$('#addEvent')
.modal();
// initialize the date range picker
$('input[name="carpool_eventDates"]').daterangepicker(
// default date range options
{ranges: {'Last 5 Days': [Date.today().add({ days: -4 }), 'today'],
'Next 5 Days': ['today', Date.today().add({ days: 4 })]}
},
// grab the selection
function(start, end) {
Session.set("showAddEventDialogue_dateRangeStart",start);
Session.set("showAddEventDialogue_dateRangeEnd",end);
});
};
JS save button click handler:
Template.add_event.events({
'click button.save-addEventDialogue': function(e, tmpl) {
// Get the date range selection from the session
var start = Session.get("showAddEventDialogue_dateRangeStart");
var end = Session.get("showAddEventDialogue_dateRangeEnd");
// Do something with the dates
// Clear the dates from the session now that we are done with them
Session.set("showAddEventDialogue_dateRangeStart","");
Session.set("showAddEventDialogue_dateRangeEnd","");
// Close the dialogue
Session.set("showAddEventDialogue", false);
}
});
Is this a good way to do this? Or is there a better way?
Thanks.
You could use jQuery's .data() to store the daterangepicker data on the original <input> element, rather than in Session. So you could rewrite your "grab the selection" code thus:
// grab the selection
function(start, end) {
$('input[name="carpool_eventDates"]')
.data("showAddEventDialogue_dateRangeStart", start)
.data("showAddEventDialogue_dateRangeEnd", end);
});
Then you retrieve the data from the element, rather than from Session:
// Get the date range selection from the element
var start = $('input[name="carpool_eventDates"]').data("showAddEventDialogue_dateRangeStart");
var end = $('input[name="carpool_eventDates"]').data("showAddEventDialogue_dateRangeEnd");
And assuming the <input> is discarded when the modal is closed and template destroyed, you have no Session or other variables to clean up.