Change ng-model before submit - javascript

I have simple model that submits a form that are all from a select I am using an ng-repeat like so:
'Ctrl'
isdom.scheduleOptions = ['Pass', 'N/A'];
'html'
<select ng-model="isdom.isdomForm.isDom101">
<option ng-repeat="option in isdom.scheduleOptions" value="{{option}}">{{option}}</option>
</select>
The person who has built the api end point is asking for the data in this format:
"outcomes": [
{ "itemNo": "is11", "outcome": "Pass" }
,
{ "itemNo": "is12", "outcome": "Pass" }...
How can I do this when my model is like so?
{
"isDom11": "N/A",
"isDOm12": "Pass",...
}
I thought about try to get all the elements in the model that start with isDom and pushing them into an outcomes array that has been modified into objects to copy the format required.
Is there a different way I can use ng-repeat to achieve this?

You could use ng-options for populating the select.
See: ngOptions or select
So it should be something like this:
$scope.isdom.scheduleOptions = [
{ "itemNo": "is11", "outcome": "N/A" }
,
{ "itemNo": "is12", "outcome": "Pass" }
];
<select ng-model="isdom.isdomForm.isDom101"
ng-options="item as item.outcome for item in isdom.scheduleOptions track by item.itemNo"></select>

Try using the (key, value) syntax as given in angular docs.
Key value in ng-repeat
(key, value) in expression –
where key and value can be any user defined identifiers, and expression is the scope expression giving the collection to enumerate.
For example: (name, age) in {'adam':10, 'amalie':12}.
Your example,
isdom.scheduleOptions = {
"isDom11": "N/A",
"isDOm12": "Pass",...
}
<select ng-model="isdom.outcomes">
<option ng-repeat="(itemNo, outcome) in isdom.scheduleOptions" value="{{outcome}}">{{outcome}}</option>
</select>

Related

get select value from a drop with angulars reads error

I'm trying to get the selected value from a drop down list with angularjs. When I select the value I get this error angular.min.js:108 TypeError: Cannot read property 'ftype' of undefined
HTML
<select name="select" ng-model="queryBy" ng-change="get_search_value(item)">
<option ng-repeat="item in filter" value="{{item.ftype}}">{{item.ftype}}</option>
</select>
JS
$scope.search_type='';
$scope.filter = [
{ id: 1, ftype: "Complaint Type"},
{ id: 2, ftype: "Region" },
{ id: 3, ftype: "District"},
];
$scope.get_search_value=function(item){
$scope.search_type=item.ftype;
alert(item.ftype)
}
My guess is item is invisible on the level of <select>. Whatever is in the <option>(so, the 'item') should be saved in the ng-model value, which is queryBy. Why are you passing item to the get_search_value? Try acessing the queryBy in the get_search_value function instead
I think you've misunderstood AngularJS... It does all of this for you. You don't need to update a separate value and you don't need a change event to do this for you.
Here is what I think you're trying to achieve:
HTML
<select name="select" ng-model="queryBy">
<option ng-repeat="item in filter" value="{{item.ftype}}">{{item.ftype}}</option>
</select>
JavaScript
$scope.filter = [
{ id: 1, ftype: "Complaint Type"},
{ id: 2, ftype: "Region" },
{ id: 3, ftype: "District"}
];
// you can access the selected value by using $scope.queryBy
That's right, just using $scope.queryBy (or just queryBy in your HTML) will give you the value of the selected option. As tymeJV mentioned, you can also use ngOptions instead of ngRepeat for your options. I'd also recommend looking into using ngBind instead of curly braces where you can, it will avoid the expression itself flashing before being evaluated.
You should be using ngOptions - your item is inaccessible the way you currently have it. Here's a quick refactor that should work:

Load nested JSON array into select in Vue using computed properties

Originally in my Vue component I had a series of nested if statements that would go through the JSON data to determine whether a text input should be displayed or a select based on a has_selectable_value option being true (select display) or false (text input display), and if it was a select then loop through the data and output associated options.
I have been able to change that to a computed statement which almost does everything I need it to do apart from one little thing which is to display the select options.
Here is the relevant part of the Vue Code:
<template v-else-if="searchtype == 9">
<select v-for="service in selectableServices" class="form-control" v-model="searchvalue" required>
<option value="">Select A Location</option>
<option v-for="sl in selectableLocations" :value="sl.location_id">{{sl.name}}</option>
</select>
<input v-for="service in nonSelectableServices" class="form-control" v-model="searchvalue" placeholder="Enter Search Value" required>
</template>
The current computed functions:
services: function () {
var ret = []
this.countries.forEach(function(country) {
country.states.forEach(function(state) {
state.services.forEach(function(service) {
ret.push(service)
});
});
});
return ret;
},
selectableServices: function () {
return this.services.filter(service => service.id == this.service && service.has_selectable_location);
},
nonSelectableServices: function () {
return this.services.filter(service => service.id == this.service && !service.has_selectable_location);
},
selectableLocations: function () {
// Filter one more level down
return this.selectableServices.map(service => service.selectablelocations);
},
This is the JSON data structure I am working with as well (I cut it back to the relevant parts for this part of the code):
[
{
"id": 1,
"name": "Country Name",
"states": [
{
"id": 1,
"name": "State Name",
"services": [
{
"id": 1,
"name": "Service Name",
"has_selectable_location": 1,
"selectablelocations": [
{
"id": 1,
"name": "Selectable Location A",
},
]
}
]
}
]
}
]
Using a Vue plugin for Chrome I can see that the computed function selectableLocations loads an array containing the individual locations, but the existing v-for statement isn't able to function correctly. Instead I still need to go down one more level which I can do by adding an extra v-for loop like so:
<template v-for="selectableLocationsList in selectableLocations" >
<option v-for="sl in selectableLocationsList" :value="sl.location_id">{{sl.name}}</option>
</template>
Everything displays correctly, but I am not sure if this is best practice as I was hoping to do as much of this in a computed function as possible and ideally only require a single v-for statement. But if it's not possible like that I understand and I can leave it as is.
Thank you in advance.
Edit: After more testing and research I have come up with this code that works as I had desired:
var formArray = []
var locationsArray = this.servicesArray.filter(service => service.id == this.service);
locationsArray.map(service => service.selectablelocations);
locationsArray.forEach(function(selectableLocations) {
selectableLocations.selectablelocations.forEach(function(location) {
formArray.push(location)
});
});
return formArray;
Is there a way I can refactor this further and make it a bit cleaner?
Solely considering the code you posted after the Edit , the code can be refactored this way:
let formArray = [];
formArray = this.servicesArray
.filter(service => service.id == this.service)
.map(service => service.selectablelocations)
.reduce((prev, curr) => prev.concat(curr))
return formArray
Note that the map you used doesn't do anything as Array.prototype.map only returns a new array, but you didn't assign it to anything.

Angular select and ng-options

I have this angular select:
<select ng-model='obj.status' ng-options='status.code as (status.code + " " + status.phrase) for status in status_codes.data track by status.code'>`
My $scope.status_codes is like this:
data: [
{
"code":"100",
"phrase":"...",
"spec_title":"RFC7231#6.2",
"spec_href":"http://tools.ietf.org/html/rfc7231#section-6.2"
}
...
]
My $scope.obj.status is updated to "300" or "100" or whatever as I change my select, but the select display is always blank. So, the model updates to the selected value of the select input but the input does not show the currently selected value, it shows a blank item.
If i change ng-options to be ng-options='status as (status.code ...' it works, but I only want status.code in my model, not the whole status array. What gives?
I have {{obj | json }} in my HTML and it reads:
obj = {
"name": "",
"description": "",
"payload": "",
"status": "200",
"responseHeaders": {
"entry": [
{
"key": "",
"value": ""
},
{
"key": "",
"value": ""
}
]
}
}
Remove track by.
From the Docs:
Be careful when using select as and track by in the same expression.
My best guess is that the as uses a normal value, like "300", but the track by is using a typed value, like "int:300". Removing one or the other should do it, preferably the track by.
They are giving this as an example:
This will work:
<select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
but this will not work:
<select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
According to the docs here: https://docs.angularjs.org/api/ng/directive/ngOptions:
select as label for value in array
So in your example this should work (you will get code value as select value in model):
status.code as (status.code + " " + status.phrase) for status in status_codes.data
track by should be used when you have object as value in model, array of objects for options and you want to match current model value to one of objects in array.

Ng-repeat with a Json file using angularjs?

I have json file called brands.json:
{
"brands": {
"Honda": [
"Accord",
"Civic"
],
"Porsche": [
"Cayenne",
"Cayman"
]
}
}
Im trying to iterate through this list and list the brand(e.g. Honda and Porsche) and render using HTML lists.
<li ng-repeat="brands in items">{{brands}}</li>
JS:
$scope.items= [];
$http.get('brands.json').then(function(response) {
$scope.items =response.data.brands;
});
This code works fine but it displays the arrays inside the brand names e.g. instead if displaying Honda it displays ["Accord", "Civic"]. I want it to display the brand names only.
<li>Honda</li>
<li>Porsche</li>
Try:
<li ng-repeat="(key, value) in items">{{key}}</li>
Quouted from the docs:
(key, value) in expression – where key and value can be any user
defined identifiers, and expression is the scope expression giving the
collection to enumerate.
For example: (name, age) in {'adam':10, 'amalie':12}.

How do I define select option values in AngularJS

...while maintaining model bindings?
I have a select menu like so:
<select class="form-control" ng-model="activeTask" ng-options="task.title for task in tasks"> </select>
That populates some text like so:
<span>{{activeTask.title}}</span>
The Projects resource grabs some json here (which is working fine):
function TimerCtrl($scope, Projects) {
$scope.projects = Projects.get({}, {isArray:true}, function(projects) {
$scope.tasks = $scope.projects[0].tasks;
$scope.activeProject = $scope.projects[0];
$scope.activeTask = $scope.tasks[0];
});
}
This is the Projects service (which is working fine as well):
angular.module('projectServices', ['ngResource']).
factory('Projects', function($resource) {
return $resource('data/projects.json', {}, {
get: {method:'GET', isArray:true}
});
});
and this is the JSON (which is also fine):
[
{
"title":"Chores",
"url_title":"chores",
"category":"Home",
"tasks": [
{"title":"Cleaning", "url_title":"cleaning"},
{"title":"Yard Work", "url_title":"yard_work"},
{"title":"Walking the Dogs", "url_title":"url_title"}
]
},
{
"title":"Personal Website",
"url_title":"personal_website",
"category":"Work",
"tasks": [
{"title":"Design", "url_title":"design"},
{"title":"Front End Dev", "url_title":"front_end_dev"},
{"title":"Node Dev", "url_title":"node_dev"},
{"title":"PHP Dev", "url_title":"php_dev"}
]
}
]
Everything works fine with the numeric values that Angular automatically creates.
My problem is...the values need to be the url-friendly string task.url_title but the option text should be task.title.
Any help would be greatly appreciated. I want to go drink a beer!
So, here's the solution I went with:
I used the task object itself as the value like so:
<select class="form-control" ng-model="activeTask" ng-options="task as task.title for task in tasks">
This allowed me to easily bind the span value to display the task title, not url_title:
<span>{{activeTask.title}}</span>
Thanks to #sza for his pointing me in the right direction. His suggestions are in the comments of the correct answer.
You can change the comprehension expression to
ng-options="task.url_title as task.title for task in tasks"
Working Demo
You need to use ng-options="...". Also use ng-model="..." or otherwise it won't work.
Here's the breakdown of it:
<select ng-options="ITEM.VALUE as ITEM.LABEL for ITEM in ITEMS" ng-model="val">
<option>placeholder value which goes at the top of the element</option>
</select>

Categories

Resources