Here is my select:
<select class="dropdownInForm" ng-model="vehicle">
<option ng-repeat="vehicle in vehicles" value="vehicle.VehicleID">{{vehicle.VehicleName}}</option>
</select>
Here is how I am loading the data in my angular controller:
$http.post('VehicleEdit.aspx/GetVehicles', { vendorID: $scope.vendorID, placeID: $scope.placeID})
.then(function (response) {
$scope.vehicles = response.data;
$scope.vehicle = $scope.vehicles[0];
})
And here is what response.data contains:
"[{"VehicleID":1,"VehicleName":"test1","IsActive":false},{"VehicleID":1,"VehicleName":"test2","IsProgrammatic":true}]"
The pull from the database is working as I am debugging it in Chrome and can see that $scope.vehicles is populated with the above JSON. However, this dropdown will not populate no matter what I try.
Where am I going wrong?
EDIT --
I should have noted that I did try it this way as well, without any luck:
<select class="dropdownInForm" ng-model="vehicle" ng-options="vehicle.VehicleId as vehicle.VehicleName for vehicle in vehicles"></select>
Here is the WebMethod that retuns the JSON:
[WebMethod]
public static string GetVehicles(int placeID, int vendorID)
{
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
DataSet vehiclesData = VehicleLogic.GetListOfVehicles(placeID, vendorID);
List<Vehicle> vehicles = new List<Vehicle>();
foreach(DataRow row in vehiclesData.Tables[0].Rows)
{
Vehicle vehicle = new Vehicle()
{
VehicleID = Convert.ToInt32(row["VehicleID"]),
VehicleName = row["VehicleName"].ToString().Trim(),
IsProgrammatic = Convert.ToBoolean(row["IsProgrammatic"])
};
vehicles.Add(vehicle);
}
return jsonSerializer.Serialize(vehicles);
}
Try using ng-options
<select ng-model="vehicle" ng-options="k as k.VehicleName for k in vehicles" >
</select>
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.vehicles = [{
"VehicleID": 1,
"VehicleName": "test1",
"IsActive": false
}, {
"VehicleID": 1,
"VehicleName": "test2",
"IsProgrammatic": true
}];
$scope.vehicle = $scope.vehicles[0];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<select ng-model="vehicle" ng-options="vehicle as vehicle.VehicleName for vehicle in vehicles"></select>
<div>
Selected Vehicle: {{vehicle | json}}
</div>
</div>
value is not an Angular directive so you have to use {{vehicle.VehicleID}} when setting the value for your <option> elements. However, a much better approach would be to use ng-options:
<select class="dropdownInForm" ng-model="vehicle" ng-options="vehicle.VehicleID as vehicle.VehicleName for vehicle in vehicles"></select>
try to not use same var name for ng-model=vehicle" and ng-repeat="vehicle as ...
Related
New to ASP.NET Core MVC: Trying to bind the result of a sql query (on my Controller) and added to a ViewBag, to an Html dropdown (dropdown B). The Action method is triggered based on a change in another dropdown (dropdown A) using Ajax.
View (if change in dropdown A):
$.ajax({
type: "POST",
url: "/Home/GetBrandsForDropdown",
data: null,
success: function (result) {
alert('Success')
},
error: function (req, status, error) {
alert('No Success')
}
});
Note: Alert is 'No Success" when I run it.
Controller:
public IActionResult GetBrandsForDropdown()
{
var content = from b in Context.Brands
select new { b.BrandNumber, b.BrandName };
ViewBag.BrandListing = content.Select(c => new SelectListItem
{
Text = c.BrandName,
Value = c.BrandNumber.ToString()
}).ToList();
return View();
}
Note: ViewBag.BrandListing includes values when I debug.
Trying but unsuccessful to get the values in the ViewBag into the following:
<select class="dropdown form-control" onchange="getOption()" name="brandDDL"
id="ddlBrandName"style="background-color: #E6E6E6;
font-size: small; color: black; font-weight: bold;
border: double">
This seems to be something that should be easily solved but I'm having no luck in getting my desired result.
Any/All help would be very much appreciated.
Jack
Note: Alert is 'No Success" when I run it.
I guess there isn't a view page for GetBrandsForDropdown this action. If you directly return View() in an action, there must be a View with the same name (here should be GetBrandsForDropdown.cshtml), otherwise it will raise a 500 server side error, and certainly it enters the ajax error function.
In addition, ViewBag will not work here, since it is the server side codes, which is already completed when the page loaded.
I suggest you can just return the content in the json format, then append the options to dropdown B.
Below is a simple demo:
View:
#{
ViewData["Title"] = "Home Page";
}
<h1>Dropdown A</h1>
<select id="dropdownA" class="dropdown form-control" onchange="getDropdownB()">
<option>A1</option>
<option>A2</option>
</select>
<h1>Dropdown B</h1>
<select id="dropdownB" class="dropdown form-control" onchange="getOption()">
</select>
#section scripts{
<script>
function getDropdownB() {
$.ajax({
type: "POST",
url: "/Home/GetBrandsForDropdown",
data: null,
success: function (result) {
$.each(result, function (key, value) {
$("#dropdownB ").append($("<option />").val(value.brandNumber).text(value.brandName));
})
alert('Success')
},
error: function (req, status, error) {
alert('No Success')
}
});
}
</script>
}
Controller:
public IActionResult GetBrandsForDropdown()
{
var content = (from b in Context.Brands
select new { b.BrandNumber, b.BrandName }).ToList();
return Json(content);
}
Result:
An easy way to do it is loop through the viewbag;
<select class="dropdown form-control" onchange="getOption()" name="brandDDL" id="ddlBrandName"style="background-color: #E6E6E6; font-size: small; color: black; font weight: bold; border: double">
#foreach(var item in ViewBag.BrandListing){
<option value="#item.Value">#item.Text</option>
}
</select>
I want to populate a second select tag based on the selected option from the first select tag. When i choose from the first select tag, I get the correct response from the API but the variable that i declared in the component does not get updated. Every other variables get updated accordingly. When i use vue-resource, the variable gets updated only when i make alternate choice in the first select based on the previous chosen option. No success using axios. Below is the trimmed version of sample code:
<label class="col-sm-2 control-label">Bind</label>
<div class="col-sm-10">
<select class="form-control m-b" name="DataSource" v-on:change="FetchFields" V-model="BindTo">
<option value="0" selected="selected">Select a data source</option>
<option v-for="Template in Templates" :value="Template.Id" :key="Template.Id">{{ Template.TName }}</option>
</select>
</div>
<label class="col-sm-2 control-label">Data Source</label>
<div class="col-sm-10">
<select class="form-control m-b" name="Field" v-model="FieldToBind">
<option value="0" selected="selected">Select a Field</option>
<option v-for="Field in TemplateCustomFields" :value="Field.Id" :key="Field.Id">{{ Field.CName }}</option>
</select>
</div>
VueJS Part
data: () => {
return {
TemplateCustomFields: [],
CustomFieldTypeSelected: '',
ShowAdditionalFieldChoice: false,
Templates: [],
BindTo: '',
FieldToBind:'',
};
},
methods:{
FetchFields() {
console.log(this.BindTo);
if (this.BindTo != "0") {
axios({
method: 'get',
url: 'http://localhost:57802/api/gettemplatebyid',
params: {
Id: this.BindTo
}
}).then(function (response) {
this.TemplateCustomFields = response.data
})
}
}
}
You have a scoping issue in your promise's then method. Callbacks in JavaScript create their own execution context, so this does not refer to the Vue instance. To solve this you can either, use an arrow function which does not create a new this:
FetchFields() {
if (this.BindTo != "0") {
axios({
method: 'get',
url: 'http://localhost:57802/api/gettemplatebyid',
params: {
Id: this.BindTo
}
}).then(response => {
this.TemplateCustomFields = response.data
})
}
Or you can assign this to something:
FetchFields() {
var self = this;
if (this.BindTo != "0") {
axios({
method: 'get',
url: 'http://localhost:57802/api/gettemplatebyid',
params: {
Id: this.BindTo
}
}).then(function(response) {
self.TemplateCustomFields = response.data
})
}
Or you can use bind:
FetchFields() {
if (this.BindTo != "0") {
axios({
method: 'get',
url: 'http://localhost:57802/api/gettemplatebyid',
params: {
Id: this.BindTo
}
}).then(function(response) {
this.TemplateCustomFields = response.data
}.bind(this))
}
I have a form in weather that would have had the condition User add as many lines he needs. He clicks a button and an input is added below the other.
I can do this using jQuery, but I would prefer to use the resources of Meteor. Is it possible to do?
Yes it is, here is an example from one of my apps using the underscore package
In the main template:
<template name="ask">
{{#each answerArray}}
{{>answer}}
{{/each}}
<button id="addItem">Add item</button>
</template>
<template name="answer">
<div class="input-group pt10">
<input class="form-control answer" maxlength="30" placeholder="Answer (max 30 chars)" name="answer" />
<span class="input-group-btn">
<button class="btn btn-danger delButton" id="{{id}}" data-id="{{id}}" type="button">Delete</button>
</span>
</div>
</template>
In the js file:
Template.ask.created = function () {
Session.set('action', 'ask');
answerArray = [ //adding at least two items but it could also be empty
{
id: Random.id(), //using this to give an unique id to the control
value: ''
},
{
id: Random.id(),
value: ''
}
];
Session.set('answerArr', answerArray);
}
And the click event:
Template.ask.events = {
'click #addItem': function () {
var answerArray = Session.get('answerArr');
answerArray.push({
id: Random.id() //just a placeholder, you could put any here
});
Session.set('answerArr', answerArray);
}
}
And finally the helper:
Template.ask.helpers({
answerArray: function () {
var answerArray = Session.get("answerArr")
while (answerArray.length < 2) { //i chose to have it between 2 and 6, you can remove these
answerArray.push({
id: Random.id()
})
}
while (answerArray.length > 6) { // maximum
answerArray.pop();
}
Session.set('answerArr', answerArray);
return answerArray;
}
}
This will reactively increase the number of inputs. After that, if you want to process the inputs you could do the following, on a submit form event or button click:
'click #saveQ': function (e) {
e.preventDefault();
var arr = [];
_.each($('.answer'), function (item) {
if ($(item).val() != '')
arr.push({
answer: $(item).val(), //this you customize for your own purposes
number: 0
})
});
And also if you want to delete an input from the page you can use:
Template.answer.events = {
'click .delButton': function (e) {
var thisId = $(e.target).attr("id");
var answerArray = Session.get('answerArr');
var filteredArray = _.filter(answerArray, function (item) {
return item.id != thisId;
});
Session.set('answerArr', filteredArray);
}
}
I have a form with a select populated with options. I want to bind it to a model using backbone.stickit but the documentation show how to populate the select on the binding configuration. I can't found an easy way to bind the model with my prepopulated select.
This is my html
<div id="main">
<form id="formulario">
<input id="test1" type="text" />
<select id="test2">
<option value="0">a</option>
<option value="1">b</option>
</select>
</form>
<div id="value-test1"></div>
<div id="value-test2"></div>
</div>
This is a working example based on the documentation, but not what I need
var Model = Backbone.Model.extend({});
var View = Backbone.View.extend({
el: $('#main'),
bindings: {
'#test1': 'test1',
'#value-test1': 'test1',
'#test2': {
observe:'test2',
selectOptions: {
collection: function() {
return [
{value: 0, label:'a'},
{value: 1, label:'b'}
];
}
}
},
'#value-test2': 'test2'
},
render: function() {
this.stickit();
}
});
var model = new Model({test1: 'test', test2: 0});
var view = new View({model: model}).render();
http://jsfiddle.net/camilosw/nDjHh/
I tried to obtain the option values from the select on the binding configuration using jquery but doesn't work
var Model = Backbone.Model.extend({});
var View = Backbone.View.extend({
el: $('#main'),
bindings: {
'#test1': 'test1',
'#value-test1': 'test1',
'#test2': {
observe:'test2',
selectOptions: {
collection: function() {
options = $("#test2 option").map(function(){
return {value: this.value, label: this.text};
}).get();
return options;
}
}
},
'#value-test2': 'test2'
},
render: function() {
this.stickit();
}
});
var model = new Model({test1: 'test', test2: 0});
var view = new View({model: model}).render();
http://jsfiddle.net/camilosw/2EYV7/2
It worked, but I think it will be a mess on forms with many selects
window.options = $("#test2 option").map(function(){
return {value: this.value, label: this.text};
}).get();
var Model = Backbone.Model.extend({});
var View = Backbone.View.extend({
el: $('#main'),
bindings: {
'#test1': 'test1',
'#value-test1': 'test1',
'#test2': {
observe:'test2',
selectOptions: {
collection: function() {
return window.options;
}
}
},
'#value-test2': 'test2'
},
render: function() {
this.stickit();
}
});
var model = new Model({test1: 'test', test2: 0});
var view = new View({model: model}).render();
http://jsfiddle.net/camilosw/Y3aEF/1
What is the best way to bind a prepopulated select to a model?
I tried only with backbone.stickit, it's easier with another library?
Stickit actually binds values as data to select-options instead of using the value html attribute. The reasoning behind this is that in rich apps, you often want to use different types of data for option values. For example, you may want an option to represent a JavaScript Object or Array which is not an easy value to serialize to an html attribute; or you may want to assign the attribute value to the Number 2, but because of type coercion when it is saved as an attribue it will be converted to the String "2". Also, since Stickit is going to parse/own the select-options, it makes sense to let Stickit render the options instead of rendering/processing it in two places (not to mention iterating in a template is ugly).
That said, this request is common enough that I'm convinced to support pre-rendered select-options. Can you open a new issue, and I'll get something out on master within the next couple of days?
EDIT: This is being actively worked on, now.
I'm having trouble getting Meteor.publish to update in response to a changing form field. The first call to publish seems to stick, so the query operates in that subset until the page is reloaded.
I followed the approach in this post, but am having no luck whatsoever.
Any help greatly appreciated.
In lib:
SearchResults = new Meteor.Collection("Animals");
function getSearchResults(query) {
re = new RegExp(query, "i");
return SearchResults.find({$and: [ {is_active: true}, {id_species: {$regex: re}} ] }, {limit: 10});
}
In client:
Session.set('query', null);
Template.searchQuery.events({
'keyup .query' : function (event, template) {
query = template.find('.query').value
Session.set("query", query);
}
});
Meteor.autosubscribe(function() {
if (Session.get("query")) {
Meteor.subscribe("search_results", Session.get("query"));
}
});
Template.searchResults.results = function () {
return getSearchResults(Session.get("query"));
}
On server:
Meteor.publish("search_results", getSearchResults);
Template:
Search for Animals
<body>
{{> searchQuery}}
{{> searchResults}}
</body>
<template name="searchQuery">
<form>
<label>Search</label>
<input type="text" class="query" />
</form>
</template>
<template name="searchResults">
{{#each results}}
<div>
{{_id}}
</div>
{{/each}}
</template>
Update [WRONG]
Apparently, the issue is that the collection I was working with was (correctly) generated outside of Meteor, but Meteor doesn't properly support Mongo's ObjectIds. Context here and related Stackoverflow question.
Conversion code shown there, courtesy antoviaque:
db.nodes.find({}).forEach(function(el){
db.nodes.remove({_id:el._id});
el._id = el._id.toString();
db.nodes.insert(el);
});
Update [RIGHT]
So as it turns out, it was an issue with RegExp / $regex. This thread explains. Instead of:
function getSearchResults(query) {
re = new RegExp(query, "i");
return SearchResults.find({$and: [ {is_active: true}, {id_species: {$regex: re}} ] }, {limit: 10});
}
At the moment, one needs to do this instead:
function getSearchResults(query) {
// Assumes query is regex without delimiters e.g., 'rot'
// will match 2nd & 4th rows in Tim's sample data below
return SearchResults.find({$and: [ {is_active: true}, {id_species: {$regex: query, $options: 'i'}} ] }, {limit: 10});
}
That was fun.
PS -- The ddp-pre1 branch has some ObjectId functionality (SearchResults = new Meteor.Collection("Animals", {idGeneration: "MONGO"});)
Here's my working example:
UPDATE the original javascript given was correct. The problem, as noted in the comments, turned out to be that meteor doesn't yet support ObjectIds.
HTML:
<body>
{{> searchQuery }}
{{> searchResults}}
</body>
<template name="searchQuery">
<form>
<label>Search</label>
<input type="text" class="query" />
</form>
</template>
<template name="searchResults">
{{#each results}}
<div>
{{id_species}} | {{name}} - {{_id}}
</div>
{{/each}}
</template>
Javascript:
Animals = new Meteor.Collection("Animals");
function _get(query) {
re = new RegExp(query, "i");
console.log("rerunning query: " + query);
return Animals.find({$and: [ {is_active: true}, {id_species: {$regex: re}} ] }, {limit: 10});
};
if (Meteor.isClient) {
Session.set("query", "");
Meteor.autosubscribe(function() {
Meteor.subscribe("animals", Session.get("query"));
});
Template.searchQuery.events({
'keyup .query' : function (event, template) {
query = template.find('.query').value
Session.set("query", query);
}
});
Template.searchResults.results = function () {
return _get(Session.get("query"));
}
}
if (Meteor.isServer) {
Meteor.startup(function() {
if (Animals.find().count() === 0) {
Animals.insert({name: "panda", is_active: true, id_species: 'bear'});
Animals.insert({name: "panda1", is_active: true, id_species: 'bearOther'});
Animals.insert({name: "panda2", is_active: true, id_species: 'bear'});
Animals.insert({name: "panda3", is_active: true, id_species: 'bearOther'});
}
});
Meteor.publish("animals", _get);
}