Using ng-option with sorting and custom text - angularjs

I have the following ng-repeat:
<select class="action-dropdown fade" ng-model="item_value">
<option value="" disabled>Choose an Step</option>
<option ng-repeat="step in steps | orderBy:'+step_number'" ng-if="step.step_number >= active_step" value="{{$index}}">Step {{step.step_number}}</option>
</select>
I am attempting to change this to an ng-option because the following option is popping up and I think this might fix the issue:
<option value="? string:5 ?"></option>
I'm trying to wrap my head around how to include my ng-if statement with the ng-option and to use the word Step $index when displaying the option.
The comprehension expressions are just blowing my mind and I was wondering if anyone could help me out.
This is what I have so far:
<select class="action-dropdown fade" ng-model="item_value" ng-options="$index as step.step_number for step in steps" required>
<option value="" disabled>Choose a Step</option>
</select>

look the snipped as I've commented
I think that the best way (cleaner way) is populate the steps list on change active_step. To access the index you can use the (key,value) syntax
select as label for (key , value) in object
Doc: https://docs.angularjs.org/api/ng/directive/ngOptions
angular.module('app', [])
.controller('DefaultController', function () {
this.item_value = null;
this.steps = [
{ step_number: 5 },
{ step_number: 2 },
{ step_number: 6 },
{ step_number: 3 },
{ step_number: 1 },
{ step_number: 4 },
]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div data-ng-controller="DefaultController as ctrl">
<select ng-model="ctrl.item_value" ng-options="step as 'Step ' + index for (index, step) in ctrl.steps | orderBy:'+step_number'" required>
<option value="" disabled>Choose a Step</option>
</select>
Selected: {{ ctrl.item_value }}
</div>
</div>

Related

Vue v-for: Dynamicly fill HTML with event handler (#change) from an array into a component template

This is my current setup:
HTML
<question
v-for="question in questions"
v-bind:id="question.id"
v-bind:title="question.title"
v-bind:statement="question.statement"
v-bind:interaction="question.interaction"
#onchange-vg="onChangeVg"/>
</question>
Definition of <question>
var questionComponent = Vue.component('question', {
props: ['id', 'title', 'statement', 'interaction', 'currentQuestion'],
template: `
<div :id="'question-' + id">
<div class="flex my-3">
<div class="py-0"><span>{{ id }}</span></div>
<div>
<p>{{ title }}</p>
<div :class="{'hidden':(id !== this.$parent.currentQuestion), 'block':(id === this.$parent.currentQuestion)}">
<p>{{ statement }}</p>
<span v-html="interaction"></span>
</div>
</div>
</div>
</div>
`
});
Vue
var app = new Vue({
el: '#app',
data() {
return {
vg: null,
currentQuestion: 1,
questions: [
{
id: 1,
title: 'Question 1',
statement: 'Details for question 1',
interaction: `
<select ref="vb-art" #change="$emit('onchange-vg')">
<option disabled value="" selected>Make a choice</option>
<option value="red">Red</option>
<option value="blue">Blue</option>
</select>
`
},
{
title: 'Question 2',
statement: 'Details for question 2',
interaction: `
<select ref="vb-art" #change="$emit('onchange-vg')">
<option disabled value="" selected>Make a choice</option>
<option value="black">Black</option>
<option value="white">White</option>
</select>
`
},
],
}
},
methods: {
onChangeVerguetungsart() {
console.log("Value: " + event.target.value);
currentQuestion++;
},
},
});
Everything is rendered fine. My problem is, that the event handler #change in <select ref="vb-art" #change="$emit('onchange-vg')"> does not fire.
Whe I replace <span v-html="interaction"></span> whit the whole <select ref="vb-art" #change="$emit('onchange-vg')">...</select> code from interaction every thing works fine.
The interactions may be different from question to question. It could be an , a or just a simple link. That's why i try to put the code into the array and not to the component definition.
How can I solve this issue, so that <span v-html="interaction"></span> accepts the event handler from a code snippet that is delivered by an array value?
You should avoid v-html. v-html bind just plain HTML, not Vue directives.
For you case v-html is not necessary. Make array of options from interaction property and generate your markup by vue template.
interaction: [
{value: 'red', label: 'Red'},
{value: 'blue', label: 'Blue'}
]
and in your component
<select ref="vb-art" #change="$emit('onchange-vg')">
<option disabled value="" selected>Make a choice</option>
<option v-for="{value, label} in interaction" :key="value" :value="value">{{ label }}</option>
</select>
update:
IF you have dynamic content, then slot is your friend. (Refer docs
https://v2.vuejs.org/v2/guide/components-slots.html for more examples)
Your component:
<div>
<p>{{ title }}</p>
<div>
<p>{{ statement }}</p>
<slot />
</div>
</div>
And usage
<question
v-for="question in questions"
v-bind:id="question.id"
v-bind:title="question.title"
v-bind:statement="question.statement"
v-bind:interaction="question.interaction"
>
<select ref="vb-art" #change="onChangeVg">
<option disabled value="" selected>Make a choice</option>
<option value="red">Red</option>
<option value="blue">Blue</option>
</select>
</question>
Bonus is, that you don't need to emit anything.
Btw using this.$parent is also not qood idea. Your component is coupled with parent. Use props instead.

Angular js ng-options selecting blank label. when i select it not showing selected

When i am selecting from dropdown it bind into model but the label of selection showing blank.
<select class="form-control" ng-options="data as data.field for data in reportAnalysis.categoryFields track by data.id" ng-model="reportAnalysis.testData">
<option value="" selected disabled>---Select---</option>
</select>
Any solution Please help?
As per the data that you mentioned, your select statement should be categoryFields.response. Not sure if you have already set your categoryFields to hold response object directly. Also the data that you shared has a square bracket and curly brace missing, assuming it to be a typo error. You can check working jsfiddle link for more clarity
<select class="form-control" ng-options="data as data.field for data in reportAnalysis.categoryFields.response track by data.id" ng-model="reportAnalysis.testData">
<option value="" selected disabled>---Select---</option>
</select>
jsfiddle : https://jsfiddle.net/caq0ne1d/27/
Let me know if this helped.
var app = angular.module("Profile", [])
app.controller("ProfileCtrl", function($scope) {
$scope.reportAnalysis = {}
$scope.reportAnalysis['categoryFields'] = [{
"id": 178,
"field": "Attachments",
"sort_order": 1,
"field_type": [{
"id": 178,
"type": 5,
"is_mandatory": 0,
"conditional_field_id": 0,
"conditional_field_value": ""
}]
}]
$scope.reportAnalysis['testData'] = {}
$scope.update_data = function() {
console.log($scope.reportAnalysis['testData'])
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="Profile" ng-controller="ProfileCtrl">
<select class="form-control" ng-options="data as data.field for data in reportAnalysis.categoryFields track by data.id" ng-model="reportAnalysis.testData" ng-change="update_data()">
<option value="" selected disabled>---Select---</option>
</select>
</body>

Angular js order by date dd-mm-yyyy

I want to order date. But doesn't work correctly. Date format is dd-mm-yyyy. Just order dd format doesn't check mm and yyyy. How can I solve?
JS
$scope.sortOptions = [
{
name:'Date desc',
sortCategory:'-anndate'
},
{
name:'Date asc',
sortCategory:'anndate'
}
];
HTML
<select ng-model="selectedSortType" class="custom-select">
<option value="" selected="">Select type</option>
<option value='{{opt.sortCategory}}' ng-repeat="opt in sortOptions track by $index">{{opt.name}}</option>
</select>
<div ng-repeat="i in res| orderBy:selectedSortType">
<div>{{i.anndate}}</div>
</div>
var app = angular.module('app', [])
.controller('appController', appController);
appController.$inject = ['$scope', '$window'];
function appController($scope, $window) {
$scope.title = "date sorting example";
$scope.sortOptions = [{
name: 'Date desc',
sortCategory: '2018-07-15 '
},
{
name: 'Date desc',
sortCategory: '2018-07-12 '
},
{
name: 'Date asc',
sortCategory: '2018-07-13'
}
];
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="appController">
<p>Ascending Order</p>
<div ng-repeat="i in sortOptions | orderBy:'sortCategory'">
<p>{{i.sortCategory}}</p>
</div>
<select ng-model="selectedSortType" class="custom-select">
<option value="" selected="">Select type</option>
<option value='{{opt.sortCategory}}' ng-repeat="opt in sortOptions | orderBy:'sortCategory'">{{opt.sortCategory}}</option>
</select>
<p>Descending Order</p>
<div ng-repeat="i in sortOptions | orderBy:'-sortCategory'">
<p>{{i.sortCategory}}</p>
</div>
<select ng-model="selectedSortType" class="custom-select">
<option value="" selected="">Select type</option>
<option value='{{opt.sortCategory}}' ng-repeat="opt in sortOptions | orderBy:'-sortCategory'">{{opt.sortCategory}}</option>
</select>
</div>
Try this..
Since the date in res object is in string format the filter is applying on dd value.
For entire date filter you need to convert the anndate to Date() object
Place the following code in the line below assigning res value in controller
angular.forEach($scope.res,function(item){ item.anndate = new Date(item.anndate); });
Then in html replace with below line
<select ng-model="selectedSortType" class="custom-select">
<option value="" selected="">Select type</option>
<option value='{{opt.sortCategory}}' ng-repeat="opt in sortOptions track by $index">{{opt.name}}</option>
</select>
<div ng-repeat="i in res| orderBy:selectedSortType">
<div>{{i.anndate| date : 'dd/MM/yyyy'}}</div>
</div>

two level ng-options nested object

EDIT: Using only ng-options as much as possible.
How the data looks like:
vm.category = [
0: {
label: 'Label A',
children: [
{
label: 'Label A.1',
value: 'labelA1',
}
]
}
1: {},
2: {}
]
How it will look like in the HTML. Expected HTML
<select>
<optionGroup> Label A </optionGroup>
<option value="labelA1"> Label A.1 </option>
<option value="labelA2"> Label A.2 </option>
<optionGroup> Label B </optionGroup>
<option value="labelB1"> Label B.1 </option>
</select>
How to achieve this without changing the data structure as much as possible?
I tried ng-options="category.children.label group by category.label for category in vm.categoryTree". But the output is
<select>
<optionGroup> Label A </optionGroup>
<option> undefined </option>
<optionGroup> Label B </optionGroup>
<option> undefined </option>
</select>
Easiest way would be to map the data to a format more easily used by the ng-options "group by" expression
angular.module('so', []).controller('snippet', function() {
this.categoru = [{"label":"Label A","children":[{"label":"Label A.1","value":"labelA1"}]},{"label":"Label B","children":[{"label":"Label B.1","value":"labelB1"}]}];
this.options = this.categoru.reduce((flat, group) => {
Array.prototype.push.apply(flat, group.children.map(child => {
return Object.assign({
parent: group.label
}, child);
}));
return flat;
}, []);
console.log(this.options);
});
<form ng-app="so" ng-controller="snippet as vm">
<select ng-model="vm.selected"
ng-options="opt.label group by opt.parent for opt in vm.options track by opt.value">
</select>
<pre>vm.selected = {{vm.selected | json }}</pre>
</form>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
You can do this,
<select ng-model='theModel' ng-change="display(theModel)">
<optgroup ng-repeat='group in collection' label="{{group.Name}}">
<option ng-repeat='veh in group.Fields' value='{{group.Name}}::{{veh.Name}}'>{{veh.Name}}</option>
</optgroup>
</select>
DEMO

Angular: ng-options add custom directive

I want to create a select tag with 'selected' value. I am doing this with ng-repeat since I cannot add a custom directive to ng-options. This is the code.
<select class="ng-valid ng-dirty" ng-model="selectedCity">
<option ng-repeat="city in allCities" value="{{city.id}}" after-render-cities>{{city.name}}</option>
</select>
This adds an extra option with value =?string:1? which I searched a lot. Since ng-options solves this issue, I however have to add the directive after-render-cities for each option. How can I solve this issue?
Use this
<select class="ng-valid ng-dirty" ng-model="selectedCity" ng-options="city.id as city.name for city in allCities">
</select>
for selection of first value, write following code in your controller
$scope.selectedCity = $scope.allCities[0].id;
use ng-init for solve value =?string:1?
<select class="ng-valid ng-dirty" ng-model="selectedCity" ng-init='selectedCity=allCities[0].id'>
<option ng-repeat="city in allCities" value="{{city.id}}" after-render-cities>{{city.name}}</option>
</select>
another choice you can use ng-selected fiddle
<option ng-repeat="(key,city) in allCities" ng-selected='key==0' value="{{city.id}}" after-render-cities>{{city.name}}</option>
</select>
You can create a custom directive, using select and ng-options.
Snippet:
JS:
template: "<select ng-options='item.id as item.name for item in list' ng-model='data'></select>",
HTML:
<div select-option list="list" ng-model='data'></div>
Refer to the demo here.
Try this code
Java Script
var app = angular.module('myApp', []);
app.controller('SampleController', function ($scope) {
$scope.Cities = [
{ Id: 1, Name: "New York" },
{ Id: 2, Name: "Colombo" },
{ Id: 3, Name: "Real Madrid" },
{ Id: 4, Name: "Bostan" },
{ Id: 5, Name: "Birmingham" }
];
$scope.City= 3;
});
HTML
<select ng-options="C.Id as C.Name for C in Cities" ng-model="City"></select>
Read This Blog, it has everything explained.

Resources