How do you make a Razors helper "Dropdownlist" or what arguments would have to pass to make it editable. For example if I want to scroll down it should let me or if I want type Instead it should let aswell.
#Html.DropDownList("CustomerId", null, htmlAttributes: new { #class = "form-control" } )
Also, if you I choose to use twitter-typeahead with EF razors how do use the "Editfor" so that once the user click on the right item, it sends the ID of that item to the database. In-other words, how do use a navigation property with razors "Editfor" helper.
#Html.EditorFor(model => model.CustomerId, null, "customer",new {htmlAttributes = new { #class = "form-control" } })
I will try to help you convert the basic example of the following page to a razor page equivalent.
http://twitter.github.io/typeahead.js/examples/
You must know that this jquery plugin displays just a list of strings and the user will select one of the values and then you will have to find the id using C# code. I will just show you how to implement the twitter typehead using razor pages but you will have to make some extra work in order to get the id.
First of all you will need the html part
<div id="the-basics">
<input class="typeahead" type="text" placeholder="States of USA">
</div>
Next you need to declare your list using C#.
List<string> Values = new List<string> { "Value 1", "Value 2", "Value 3" };
Now you will have the following HTML.
var substringMatcher = function(strs) {
return function findMatches(q, cb) {
var matches, substringRegex;
// an array that will be populated with substring matches
matches = [];
// regex used to determine if a string contains the substring `q`
substrRegex = new RegExp(q, 'i');
// iterate through the pool of strings and for any string that
// contains the substring `q`, add it to the `matches` array
$.each(strs, function(i, str) {
if (substrRegex.test(str)) {
matches.push(str);
}
});
cb(matches);
};
};
var states = #Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Values));
$('#the-basics .typeahead').typeahead({
hint: true,
highlight: true,
minLength: 1
},
{
name: 'states',
source: substringMatcher(states)
});
I hope it helps.
Related
Within my view I have a select box. If a certain value is selected I want more form options to appear below using #if.
#model App.ViewModels.JobVM
<div class="row">
<div class="form-group">
#Html.Label("Job Type", new { #class = "control-label" })
#Html.DropDownListFor(model => model.JobId,
new SelectList(App.ViewModels.JobVM.GetJobs(),
"Value", "Text"),
"--Choose Job Type--",
new { #class = "form-control"})
</div>
</div>
...
#if (Model.JobId == 1)
{
.... more form options
}
However when running if the select option that give Job ID 1; the form options don't render.
Is there a reason why the form options do not appear when the Select option changes? Or will I have to use javascript to accomplish this goal?
It's expected behavior as view is rendered on server once before sending data to browser. However, for displaying additional inputs you can use both methods - js or partial views (even with ajax if you need) you have to use only JavaScript to show/hide other elements of form for required cases.
The #if statement and Model.JobId executed server-side, hence Model.JobId value doesn't change when the dropdown selected value has changed because change event occurred in client-side. By handling change event with JS, you can use AJAX call to set the value and display additional form options which contained inside partial view:
jQuery AJAX call
$('#JobId').change(function () {
var jobId = $(this).val();
if (jobId == 1) {
$.ajax({
type: 'GET', // or 'POST'
url: '#Url.Action("ActionName", "ControllerName")',
data: { JobId : jobId },
success: function (result) {
$('#formoptions').html(result);
},
// other stuff
});
}
else {
$('#formoptions').empty();
}
});
Controller Action
public ActionResult ActionName(int JobId)
{
// do something
return PartialView("_FormOptions", viewmodel);
}
If the form options are already rendered together inside view, instead of using server-side #if block, simply use a <div> placeholder and toggle its visibility like this:
$('#JobId').change(function () {
var jobId = $(this).val();
if (jobId == 1) {
$('#formoptions').show(); // show form options
} else {
$('#formoptions').hide(); // hide form options
}
});
HTML
<div id="formoptions">
<!-- more form options -->
</div>
I'm trying to implement sort and search to my items, so i started with sort and it works:
Template
<button class="sort">Sort</button>
{{#each cvs}}
{{> Interviu}}
{{/each}}
JS:
Template.Interviuri.onCreated(function () {
var self = this
self.autorun(function () {
self.sortOrder = new ReactiveVar(-1)
})
Template.Interviuri.helpers({
cvs() {
const instance = Template.instance()
return Cvs.find({}, { sort: { createdAt: instance.sortOrder.get() } })
},
})
Template.Interviuri.events({
'click .sort'(event, instance) {
instance.sortOrder.set(instance.sortOrder.get() * -1)
Next i wanted to implement Search on the same page. So the best way i could found was EasySearch.
But using EasySearch, it means i must change the way my items are being displayed. And then the sort doesn't work anymore.
Template
<div class="searchBox pull-right">
{{> EasySearch.Input index=cvsIndex attributes=searchAttributes }}
</div>
{{#EasySearch.Each index=cvsIndex }}
{{> Interviu}}
{{/EasySearch.Each}}
Collection
CvsIndex = new EasySearch.Index({
collection: Cvs,
fields: ['name'],
engine: new EasySearch.Minimongo()
})
JS
cvsIndex: () => CvsIndex,
How can i have both search and sort working at the same time?
With EasySearch you can use two methods on your index, namely getComponentDict() and getComponentMethods().
With getComponentDict() you can access search definition and options:
index.getComponentDict().get('searchDefinition');
index.getComponentDict().get('searchOptions');
You also have the corresponding setters to change the search definition/option.
getComponentMethods has mehods like
index.getComponentMethods().loadMore(integer);
index.getComponentMethods().hasMoreDocuments();
index.getComponentMethods().addProps(prop, value);
index.getComponentMethods().removeProps([prop])
From that you can set your prop, say index.getComponentMethods().addProp('sort', -1) and then on the index definition, in your MongoDB engine, set the sort from that prop:
index = new EasySearch.index({
// other parameters
engine: new EasySearch.MongoDB({
sort: function(searchObject, options) {
if(options.search.props.sort) {
return parseInt(options.search.props.sort);
}
return 1;
}
})
});
See EasySearch Engines for more info.
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'm working on a project which uses ASPNET MVC 3, unobstrusive javascript and Razor
I have a partial view with Ajax.BeginForm containing fields like this:
#Html.TextBoxFor(model => model.FirstName, new { #class = "txt-input", placeholder = "Eg. First Name", maxlength = 50 })
#Html.ValidationMessageFor(model => model.FirstName, "*", new { #class = "form-comments redtxt" })
Then at the end of the form I have this:
#Html.ValidationSummary(false, "Please complete the required fields", new { #class = "form-comments redtxt" })
When I enter no value it correctly shows "*" near the textbox, and "Please complete the required fields" in the validation summary.
The problem is that when I enter a correct value only the "*" disspears and the "Please complete the required fields" remains.
I need to add this in the css in order to not show "*" nor the "Please complete the required fields" when the patial view is loaded for the first time.
.validation-summary-valid
{
display: none;
}
.field-validation-valid
{
display: none;
}
How can I make the validation summary dissapear when valid data is entered?
Thanks in advance! Guillermo.
As far as i understood ur problem, u can use below written code. Its just a hack.
<script>
jQuery(function () {
jQuery('form')
.find('input')
.bind('keyup', function () {
var _summary = jQuery('.form-comments');
if ($(this).valid()) {
_summary.hide();
}
else {
_summary.show();
}
})
});
</script>
As why it's still displaying I don't know.
But a quick fix is to put an if block around your #Html.ValidationSummary and check to see if the model is valid
# if(!ViewContext.ViewData.ModelState.IsValid){
#Html.ValidationSummary(false, "Please complete the required fields", new { #class = "form-comments redtxt" })
}
I usually put my validation summary in a dialog and i just don't display the dialog div if Page.IsValid is true
--Update here is a code snippet that I know works
#{ if(!ViewContext.ViewData.ModelState.IsValid){
<div id="errors" class="DisplayErrors">
#Html.ValidationSummary()
</div>
}}
<script type="text/javascript">
$(function () {
$(".Date").datepicker();
$(".button").button();
$(".DisplayErrors").dialog({ autoOpen: true, title:"Errors" });
});
</script>
I have a dojo grid which is using some editable dijit form fields. All is well, until I try ot implement an country (multi) select cell as an Tooltip Dialog; i.e., show a drop down button which opens the tooltip dialog populated with a checkbox array to select one or more country. Once checked and clicked OK, the cell should update with a list of selected countries. Obviously I'll take care of updating the server via the store later on.
I've implemented a country select tooltip dialog which works fine like so:
dojo.provide("CountrySelector");
dojo.declare(
"CountrySelector",
[dijit.form.DropDownButton],
{
label: 'Countries',
dropDown: new dijit.TooltipDialog({ execute: function() {
console.log("EXECUTE : ", arguments[0]);
this.value = arguments[0].country;
}, href:'/cm/ui/countries' }),
postCreate: function() {
this.inherited(arguments);
this.label = this.value;
dojo.connect(this.dropDown, 'onClose', function() { console.log('close'); });
console.log("CountrySelect post create", this);
},
}
);
And the grid cell is typed as:
{ name: 'Countries', field: 'targeting.countries', editable: true, hidden: false, type:dojox.grid.cells._Widget, widgetClass: CountrySelector },
All is working fine but I can't figure out how to update cell's content and store once the widget is executed. As well, I don't seem to have the row id of the updated row.
Any ideas?
Thanks,
Harel
//Layout:
gridLayout: {rows: [{name: 'Coll Name',field: 'colField', type: dojox.grid.cells.ComboBox, editable:'true', width:'8%',options: [], alwaysEditing:false}]}
//Grid Store:
this.gridStore = new dojo.data.ItemFileReadStore({data: {items: data}});
//
var setOptions = function(items, request){
this.gridLayout.rows[0].options.push('Val 1','Val 2');
this.gridLayout.rows[0].values.push('1','2');
dojo.connect(this.gridLayout.rows[0].type.prototype.widgetClass.prototype, "onChange",this, "_onComboChange");
}
this.gridStore.fetch({onComplete: dojo.hitch(this,setOptions)});
_onComboChange: function (selectedOption) {
console.info("_onComboChange: ",selectedOption);
},
// If you need to populate combos with different values you can use onItem
var getArray = function(item, request){
// populate one by one
// attach an event to each combo
}
this.gridStore.fetch({onItem: dojo.hitch(this,getArray)});
This is what i used to update my grid
var idx = yourGrid.getItemIndex(item);
if (idx >- 1) {
yourGrid.updateRow(idx);
}
More detail
every row is identified by its identifier
yourGrid.store.fetchItemByIdentity({
identity: <yourIdentity>,
onItem: function(item){
// Update your attributes in the store depending on the server response
// yourGrid.store.setValue(item, <attribute>,<value>);
var idx = yourGrid.getItemIndex(item);
if (idx >- 1) {
yourGrid.updateRow(idx);
}
}
});
I didn't set up a test with your code but you should be able to do it by just creating a method named getValue in your widget that returns the value.
Take a look at the other examples (like dojox.grid.cells.ComboBox) to get an idea of what getValue should look like.