ng-selected not working on option element with ng-repeat - html

I am using a select combobox with dynamic values from an OData response. Beccause of this I need to identify the 'highest' existing period in my response and set the selectedattribute for the relevant option item.
This selectis used as a period filter. That's why I also added an entry for 'all' periods. This can be removed in the sample and makes no difference in the behaviour.
Angular seems to evaluate the conditions etc. correct, so the element which should be selected gets the attribute selected="selected" and ng-select="true".
Nevertheless the browser selects '' by default rather than the selected element. Even if I remove the option for all periods, the browser takes the 'empty' element and not the element with the selectedattribute.
I checked other answer so similiar questions, but none of them worked and many reference ng-options instead of ng-repeat.
More information
I am using AngularJS v1.4.9 and Chrome 48.0.2564.103 m
I am using a rather large OData response in JSON format as data source, so I'd need to rewrite the code here to provide an executable example.
I'll do this if it's necesary or required.
For other reasons, which I don't want to discuss here I cannot use ng-options, so please don't suggest this.
HTML snippet - commented and indented afterwards
The other logic for sorting, ordering etc. is working fine.
<select class="semester-selection" ng-model="selectedPeriod.Period_Nav.PeriodName">
<!-- This 'empty' option can be removed. ng-selected won't work then either -->
<option ng-selected="false" value=""><Alle></option>
<option ng-selected="{{examResult.Period == getHighestPeriod()}}"
ng-repeat="examResult in examResultData.results | uniquePeriod:'Period' | orderBy:'-Period'"
value="{{examResult.Period_Nav.PeriodName}}">
<!-- Debug information -->
{{examResult.Period_Nav.PeriodName}}
{{examResult.Period == getHighestPeriod()}}
{{getHighestPeriod()}}
</option>
</select>
Generated HTML via Angular JS
The generated code looks okay, because selected="selected" and ng-select="true" as in there for the desired element.
<select class="semester-selection ng-pristine ng-valid ng-touched"
ng-model="selectedPeriod.Period_Nav.PeriodName">
<option value=""><Alle></option>
<!-- ngRepeat: examResult in examResultData.results | uniquePeriod:'Period' | orderBy:'-Period' -->
<option selected="selected" ng-selected="true" ng-repeat="examResult in examResultData.results | uniquePeriod:'Period' | orderBy:'-Period'" value="WiSe 2011/12" class="ng-binding ng-scope">
WiSe 2011/12
true
15014000
</option>
<!-- end ngRepeat: examResult in examResultData.results | uniquePeriod:'Period' | orderBy:'-Period' -->
<option ng-selected="false" ng-repeat="examResult in examResultData.results | uniquePeriod:'Period' | orderBy:'-Period'" value="SoSe 2007" class="ng-binding ng-scope">
SoSe 2007
false
15014000
</option><!-- end ngRepeat: examResult in examResultData.results | uniquePeriod:'Period' | orderBy:'-Period' -->
</select>
Result in the browser
When I open the page in the browser the combobox has still not the selected value as active, but the first or empty one.
Reduced sample for testing / fiddling around
Oh. This reduced sample works, so I need to find the issue somewhere else in the code.
var app = angular.module('ExamResultList', [ ]);
app.controller('ExamResultController', ['$scope', function ($scope) {
// Simplified sample data -> this can contain 'duplicates'
$scope.examResultData = [
{PeriodName:'WiSe 15/16', Period:8}, // fake OData OrderBy -> Highest period is the first elem
{PeriodName:'SoSe 12', Period:1},
{PeriodName:'WiSe 12/13', Period:2},
{PeriodName:'WiSe 12/13', Period:2},
{PeriodName:'WiSe 12/13', Period:2},
{PeriodName:'SoSe 13', Period:3},
{PeriodName:'WiSe 13/14', Period:4},
{PeriodName:'SoSe 14', Period:5},
{PeriodName:'WiSe 14/15', Period:6},
{PeriodName:'SoSe 15', Period:7}
];
$scope.highestPeriod = 0;
$scope.getHighestPeriod = function() {
// first element has the highest period, because the OData request has a orderby expression
return $scope.examResultData[0].Period;
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ExamResultList" id="examResultListWrapper">
<div ng-controller="ExamResultController as ExamResCtrl" id="examResultList">
<select class="semester-selection">
<option ng-selected="false" value=""><Alle></option>
<option ng-selected="{{examResult.Period == getHighestPeriod()}}"
ng-repeat="examResult in examResultData"
value="{{examResult.PeriodName}}">
{{examResult.PeriodName}}
<!-- Debug info
{{examResult.Period == getHighestPeriod()}}
{{getHighestPeriod()}}
-->
</option>
</select>
</div>
</div>

ng-selected does not take expression brackets. Use
ng-selected="examResult.Period == getHighestPeriod()"

Related

Display label displayed in options as the title of select

How to show option.Brand.Name as the title of the select field without using java script and changing the ng-model?
<select ng-model="detail.BrandId" title="" class="form-control" disabled>
<option ng-repeat="option in mainCtrl.products" ng-selected="option.Id === detail.ProductId" ng-value="option.BrandId">{{option.Brand.Name}}</option>
</select>
AngularJS and select-options
Try using ng-options AngularJS ngOptions directive within select element itself. Then you don't need to add each option element yourself using ng-repeat.
Clarification
The title-attribute belongs to the select-element and will show if you hover over the select. You would like the title to reveal the current selected option? Did I understand you correctly?
How to show option.Brand.Name as the title of the select field
Curious, where this detail.ProductId comes from? Is the brand preselected by product-id (see your code)?
ng-selected="option.Id === detail.ProductId"
Solution space
Your requirements/restrictions are:
without using JavaScript (maybe because you can't change the sources)
without changing the ng-model (because you need there only the BrandId for some database-reasons)
So since the title of the select-element has no access to the options inside, the only way to set it is depending on the current selection, i.e. your detail.BrandId. So the title can only set dynamically (depending on the current selection) by using standard-angularJS means, as:
{{ expression }} expressions
{{ expression | filter }} array-filter
Expected behavior
The only scope-variable changed by selecting is specified within select's ng-model as detail.BrandId. This will be set when user selects an option to its property BrandId. When user selects between options they will be visible with ther BrandName as label. After selection this BrandName (label of the option) should be shown as title of the entire select element.
So we need to get from detail.BrandId (selected ng-model) to related options BrandName (as this should show as title).
Possible Solution
Only way is to use standard angular expressions/filters/array-indexing to get the whole option by the selected detail.BrandId (ng-model)
Then we can lookup the option.BrandName by this equation after selected detail.BrandId === option.BrandId
var app = angular.module('app', []);
app.controller('mainCtrl', function($scope){
$scope.products = [
{Id: 0, name: 'Watson', brandId: 1, brandName:"IBM"},
{Id: 1, name: 'DB2', brandId: 1, brandName:"IBM"},
{Id: 2, name: 'Windows', brandId: 2, brandName: "Microsoft"},
{Id: 3, name: 'Office', brandId: 2, brandName: "Microsoft"}
];
$scope.detail = { ProductId: 3, BrandId: null };
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<!DOCTYPE html>
<html>
<body data-ng-app="app" data-ng-controller="mainCtrl">
<table border="1">
<tr>
<th>Product Id</th><th>Product Name</th><th>Choose Brand</th><th>Brand Id</th>
</tr>
<tr>
<td>{{detail.ProductId}}</td>
<td>{{ (products | filter: {Id: detail.ProductId})[0].name }}</td>
<td>
<select class="form-control"
ng-model="detail.BrandId"
ng-init="detail.BrandId = (products | filter: {Id: detail.ProductId})[0].brandId"
ng-options="o.brandId as ('['+ o.Id +'] '+ o.name +' : '+ o.brandName +' ('+ o.brandId +')') for o in products"
title="{{ (products | filter: {brandId: detail.BrandId})[0].brandName}}"
>
<!-- default option when not preset by detail.ProductId-->
<option value="">-- please choose brand --</option>
</select>
</td>
<td>{{detail.BrandId}}</td>
</tr>
</table>
<hr/>
<p>Product is predefined. So the brand is pre-selected by product. BUT: after brand is selected, the product-details do NOT change!</p>
Selected <strong>detail</strong>:
<pre ng-model="selected">{{detail | json}}</pre>
</body>
</html>
See also
For using ng-options, see also plunkr example.
You can register the selected option object in the ng-repeat parent scope by using as alias-expression provided by ng-repeat.
In your case you just need to do something like that:
<select ng-model="detail.BrandId"
title="{{options | selectedProductFilter : detail.ProductId}}"
class="form-control"
disabled>
<option ng-repeat="option in mainCtrl.products as options"
ng-selected="option.Id === detail.ProductId"
ng-value="option.BrandId">
{{option.Brand.Name}}
</option>
</select>
The options object will be available in your controller closure and you can display the title by using a custom filter.
angular.module("app").filter('selectedProductFilter',
function () {
return function (input, id) {
if (!input) return "";
let occurence = input.filter(function (x) {
return x.Id == id;
});
return occurence.length > 0 ? occurence[0].Brand.Name: "";
}
}
);
you need to do ng-change event in your select and call function in it that change the value of label text to the select value name. something like below
In Html
ng-change="changedValue(detail.BrandId)"
In JS
$scope.changedValue = function(item) {
//change label name here
}
fill ng-model by "option" not "option.BrandId"
then you can set title like this :
mainCtrl.products['ng-model-name'].Brand.Name
Here's how you could achive this:
(function () {
"use strict";
const app = angular.module("app", []);
app.controller("app.AppCtrl", $scope => {
$scope.selectedOption = null;
$scope.optionList = [{_id: 1, label: 'Option 1'}, {_id: 2, label: 'Option 2'}];
});
})();
body {
margin: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="app" ng-controller="app.AppCtrl">
<select title="{{selectedOption.label}}" class="form-control" ng-model="selectedOption">
<option ng-repeat="option in optionList" ng-value="option"> {{option.label}}</option>
</select>
</div>
Try using ng-init,
add ng-init to your select tag and put your object index value you want to be selected by default.
e.g.
Your code
<select ng-model="detail.BrandId" title="" class="form-control" disabled>
<option ng-repeat="option in mainCtrl.products" ng-selected="option.Id === detail.ProductId" ng-value="option.BrandId">{{option.Brand.Name}}</option>
</select>
adding following code (Suppose I want index 0 by index):
ng-init="detail.BrandId = option[0].Brand.Name"
It will look like this :
<select ng-model="detail.BrandId" ng-init="detail.BrandId = option[0].Brand.Name" title="" class="form-control" disabled>
<option ng-repeat="option in mainCtrl.products" ng-selected="option.Id === detail.ProductId" ng-value="option.BrandId">{{option.Brand.Name}}</option>
</select>
or Check these thread's
how to use ng-option to set default value of select element
How to set default value in ng-options

Dynamically show previous/next div with XQuery - recursion?

knowing community,
I want to achieve the following in short: I have a XML-file with listed pizzas inside of it (it is a kind of test file). My page has a select menu from which a user choses one pizza and the pizza size, which is then both displayed below. The content will only show up after the user has chosen. This is the function:
declare function app:showpizza2($node as node(), $model as map(*)){
let $pizza1 := request:get-parameter('selectMenu1', '')
let $size1 := request:get-parameter('size1', '')
return
for $pizza in $app:pizza//pizza
where $pizza/#id eq $pizza1
let $id := $pizza/#id
return
(<a data-key="{ $id }" class="person"><div>{ $pizza1 }</div></a>,
<div>{ $size1 }</div>)
};
With a second function I now want to build previous/next buttons which take the current shown pizza, find it inside of the XML tree and then go one step further up or down. So far I am able to show one pizza above or below with these lines:
declare function app:previousPizza($node as node(), $model as map(*)){
let $pizza1 := request:get-parameter('selectMenu1', '')
return
for $pizza in $app:pizza//pizza
where $pizza/#id eq $pizza1
let $previousPizza := $pizza/preceding::pizza[1]
return
<p>{ $previousPizza }</p>
};
The problem of course is that as a "current pizza parameter" I only take the user-chosen value from the select menu. So I guess this is a typical recursion problem because I want to have a function which always takes the current parameter after clicking on a button but I kind of really have no idea how to achieve this. Can you help out?
This is my html-file where I call these functions:
<div class="row">
<div class="col-sm-4">
<!-- form for choosing pizza -->
<form action="?">
<!-- select Pizza type -->
<select name="selectMenu1" id="pizzamenu1"
data-placeholder="Pizza wählen" style="width:150px">
<option value=""></option>
<option value="pizza1">Pizza 1</option>
<option value="pizza2">Pizza 2</option>
<option value="pizza3">Pizza 3</option>
</select>
<!-- select pizza size -->
<select name="size1" data-placeholder="Größe wählen"
style="width:150px;" onchange="this.form.submit()">
<option value=""></option>
<option value="family">Familien Pizza</option>
<option value="medium">Mittel Pizza</option>
<option value="small">Kleine Pizza</option>
</select>
</form>
</div>
</div>
<div class="row">
<div class="col-sm-4">
<!-- showpizza2 returns chosen pizza from select menu -->
<div data-template="app:showpizza2"/>
<!-- Show previous pizza -->
<div data-template="app:previousPizza"/>
</div>
</div>
Thanks.
Since the value of the user-selected pizza comes from the html list, it is in $model. Your Xquery function for the next/prev buttons should access the $model to start where you want to.
We would need to see how you call the xquery modules in your .html files, to give you a working code sample. But the problems you describe are likely originating there.
See the documentation for Using the Model to Keep Application Data

How to change select tags value when element is deleted from array?

I have select tag which takes values from array like this
<select class="groupForArchive" ng-model="selected.country">
<option ng-selected= "{{country == selected.country}}" ng-repeat="country in countrynList" value={{country}}> {{ country.name }} </option>
</select>
when I am deleting element from array(countryList) I am setting new value to this tag like this $scope.selected.country = newValue, but in select box I am getting free space like in this pictures.
before delete country from list
after delete country from list
and when I am taking select tag's ng-model I am getting correct object but I can not see it in my select box and I don't know which item is selected.
P.S newValue is array's another item(item from countrynList)
How can I fix it ?
Update AngularJS library to latest version and make changes, presented below:
angular.module('app', []).controller('ctrl', function($scope){
$scope.countrynList = [
{name:'USA'}, {name:'Spain'}, {name:'France'}, {name:'Germany'}
]
$scope.selected = {country: $scope.countrynList[0]};
$scope.Delete = function(){
var index = $scope.countrynList.indexOf($scope.selected.country);
$scope.countrynList.splice(index, 1);
$scope.selected.country = $scope.countrynList[0];
}
})
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<div ng-app='app' ng-controller='ctrl'>
<select class="groupForArchive" ng-model="selected.country">
<option ng-repeat="country in countrynList" ng-value='country'>
{{country.name}}
</option>
</select>
{{selected.country}}
<br>
<input type='button' ng-click='Delete()' value='Delete First'/>
</div>

Issue when trying to populate a drop-down with database values

I am using the following HTML to show a selected drop down with values from the database and rest of the others in the list. It shows the selected name correctly but the selected is also displayed in the list.
How to remove the second time show selected name in the drop down list? Is this a good way to use drop down menu? Here Jobcategory and Jobdetails are associated.
Im using Laravel 4.2 and this is the HTML:
// view drop down form to save data
<div class="large-6 columns">
<label>Job Category
<select name="category[]">
<option value="">Select Category</option>
#foreach(JobCategory::all() as $jcat)
<option value="{{ $jcat->id }}">{{ $jcat->name }}</option>
#endforeach
</select>
</label>
</div>
// Edit drop down form to update the selected value
<div class="large-6 columns">
<label>Job Category
<select name="category[]">
<option value="{{$jobedit->jobcategory->id}}">{{$jobedit->jobcategory->name </option>
#foreach(JobCategory::all() as $jcat)
<option value="{{ $jcat->id }}">{{ $jcat->name }}</option>
#endforeach
</select>
</label>
</div>
// database table for jobcategories
id | name
1 | Accounting/Finance
2 | Advertisement/Event Mgt.
3 | .....
// after save into jobdetails table
id | jobcategory_id | .......
1 | 5 | ...
I can retrieve the value of jobcategory in the edit form but it shows twice one in the selected value and other in the listed value of all jobcategory. This is the problem and i want only show the selected value and then rest of the others from jobcategory table without duplicate value of selected in the drop down. plz help.
// controller to to edit
public function getJobEdit($id)
{
$jobedit = JobDetail::find($id);
return View::make('employers.edit_single_jobs')->with('jobedit', $jobedit);
}
// JobDetail --model
public function jobcategory()
{
return $this->belongsTo('JobCategory');
}
// JobCategory --model
public function jobdetails()
{
return $this->hasMany('JobDetail', 'jobcategories');
}
Have a look at the Forms & HTML helper of laravel.
Generating A Drop-Down List With Selected Default
echo Form::select('size', array('L' => 'Large', 'S' => 'Small'), 'S');
where the first argument is the name of the select box. The second argument is an array of all entries in the box and the last argument determines which of the array elements is the selected one.
in your case it could look something like this:
{{ Form::select(
'categoryName',
array(
'Accounting/Finance' => 'Accounting/Finance',
'Advertisement/Event Mgt.' => 'Advertisement/Event Mgt.',
// to be continued ...
),
'$cat->category_name'
); }}
//Edit
<div class="large-6 columns">
<label>Job Category
{{ Form::select('category[]', ['' => 'Select a category'] + $all_categories, $jobedit->jobcategory->id) }}
</select>
</label>
</div>
where $all_categories should be an array of all categories as in the first example. You can get this from JobCategory::all().
This is how I set up drop-downs in my projects. I prepare the data in my controller (you'd obviously need a route and controller set up for this, I'm assuming you've done that):
Controller
public function index()
{
$categories = \Category::lists('name', 'id')->orderBy('name'); // assuming you have a Category model
view('categories', compact('categories'));
}
Then you can use the Forms and HTML helper as Peh mentioned, this isn't available as a default in Laravel 5 so you'd need to add it into your project using composer. To do so either run composer install illuminate/html or add "illuminate/html": "~5.0" to your composer.json file and then run composer install. You'd then need to add 'Illuminate\Html\HtmlServiceProvider' to config/app.php in the providers array then add 'Form' => 'Illuminate\Html\FormFacade' and 'HTML' => 'Illuminate\Html\HtmlFacade' to the aliases array in the same file. Once that's sorted you can use the Form and HTML helper in your view, as so:
View
{{ Form::select('categoryName', ['' => 'Select a category'] + $categories) }}
Your view would need to be saved as filename.blade.php if using the handlebars, otherwise echo it within <?php ?> tags.
Hope that helps you on your way.

Grails - Select menu not rendering

So I am creating 2 drop down menus, the 2nd of which dynamically changes based off the first. However, the 2nd menu does not render the change, but is providing the correct options when viewing the Post with Firebug.
Here is the function that is supposed to render the menu
def findSubtagsForTags(){
print Tag.getAll()
def tag = Tag.get(params.tag.id)
render(template: 'subtagSelection', model: [subtags: tag.subtags])
}
This method is being called in my _form.gsp template, which is called by create.gsp (both generated by grails scaffolding for the most part). Here is my code snippet where I am calling it
<g:select name="tag.id" from="${Tag.list()}" optionKey="id" optionValue="tagName"
noSelection="['':'Choose Tag']"
onchange="${remoteFunction (
controller: 'tag',
action: 'findSubtagsForTags',
params: '\'tag.id=\' + this.value',
update: 'subtagSelection'
)}" />
<td id="subtagSelection" valign="top">
<select>
<option>Choose Tag</option>
<g:select name="subtags.id" id="subtags.id" from="${[]}" optionKey="id"/>
</select>
</td>
and the subtagSelection template that is being rendered is
<g:select name="subtag.id" from="${subtags}" optionValue="name" optionKey="id" id = "subtags.id"/>
The 2nd menu on the page is always "CHoose Tag", but using Firebug, when I look at the post, this is generated
<select name="subtag.id" id="subtags.id" >
<option value="1" >Training</option>
<option value="2" >Software</option>
</select>
however, there is no change to the 2nd menu.
Under the Net Tab of firebug, This is the 'put' request called by my function
Post:
Parameters : tag.id 1
Source:
tag.id=1
Response:
<select name="subtagSelection" id="subtagSelection" >
<option value="1" >Training</option>
<option value="2" >Software</option>
</select>
Any ideas/solutions?
EDIT: Issue was resolved after changing my code around a little, using https://stackoverflow.com/a/3771240/3691484 as a reference, changing the template file among other things
Try a few modifications - see if makes any difference:
<g:select name="tag.id" from="${Tag.list()}" optionKey="id" optionValue="tagName"
noSelection="['':'Choose Tag']"
onchange="${remoteFunction (
controller: 'tag',
action: 'findSubtagsForTags',
params: "'tag.id=' + this.value",
update: 'subtagSelection'
)}"
/>
<td id="subtagSelection11" valign="top">
<div id="subtagSelection">
<g:select name="subtags.id" id="subtags.id" from="[]"
optionKey="id" noSelection="['': 'Choose Tag']" />
</div>
</td>
There was a minor issue a select within a select? - use the noSelection tag for when nothing is selected