Angular Drop Down, Select by Index - javascript

I am retrieving an unordered list and binding to a drop down here, but on instantiation I want to be able to select the 0th item in the drop down. ng-init="selectedTreatment=treatments[0]" doesn't work, as the list is reordered in the view.
<select ng-model="selectedTreatment"
ng-options="option.TreatmentName for option in (treatments | orderBy : 'TreatmentName')">
</select>
Is there an Angular way to do this?

In tour controller set the select ng-model
$scope.selectedTreatment = treatments[0].TreatmentName

One solution was to order the data in the controller, the same way as it is ordered in the view. Then in the controller I injected the $filter into the controller and did:
$scope.selectedTreatment = $filter('orderBy')($scope.treatments, 'TreatmentName')[0];
This allowed me to utilise the orderBy filter in the controller. This fixed my problem, but seems like it doesn't offer full SOC. A way to do this neatly in the view doesn't seem to be possible.

Related

Converting md-switch to md-select

I'm working on this dynamic filter system using AngularJs and trying to figure out how to convert the color and size options to be in two dropdowns (one for each category).
I've tried the following code which does successfully add the dropdown along with the options in the select box, but upon click of one of the options, it doesn't select it.
<md-select ng-model="filter[cat][value]" placeholder="val" multiple>
<md-option ng-repeat="value in getItems(cat, data)" ng-value="{{value}}" ng-init="filter[cat]={}">
{{value}}
</md-option>
</md-select>
Demo: https://codepen.io/mikelkel/pen/rwQKRm (Above code had been removed from this demo.)
There are a few issues:
According to the documentation, multiple is a boolean so it needs to be multiple="true".
value in ng-model doesn't exist in that scope since it only exists in md-option, so you can't do filter[cat][value]. If you look at the documentation for md-select you will see that when using multiple the model is an array. So if you set your ng-model to simply filter[cat] then its value will be something like ["red","yellow"].
You can then modify filterByPropertiesMatchingAND so that it does a string match against like properties (so if the shirt color is red and the filter.color array contains red then you would return true).
I forked your codepen (https://codepen.io/czema/pen/KqbpPE) and made the following changes:
Even though ng-init is frowned upon I left it, but I initialized the filter[cat] to an array rather than an object.
I removed the md-item.
I set ng-model to filter[cat] and multiple="true"
In the Javascript I modified your filterByPropertiesMatchingAND function. Now it expects $scope.filter contain arrays for each property (rather than an object with color names and boolean values). I dropped the noSubFilter function.
Use ng-options in select rather than ng-repeat on the option tag. The syntax for ng-options is a little odd, but it would be something like this in your case: ng-options="value for value in getItems(cat, data)"
Read the documentation for ngOption https://docs.angularjs.org/api/ng/directive/ngOptions
As far as why your attempt above doesn't work, probably has something to do with the ng-init, which is being executed for each option and is probably wiping out any existing data. Don't use ng-init.

Angular - replacing filters with ng-show in nested ng-repeat

I've been running into some performance issues with my Angular Material app on IE11 and have been investigating mutliple issues. I've taken some steps to rectify based on the official suggestions, but I noticed something I think is causing a lot of the issue.
We have a product page with a set of tabs that displays/hides products based on the currently selected category. The largest amount of delay happens when clicking between tabs. I think this is because the filters we apply destroy/recreate the DOM each time the tab is clicked off of. I'd like to use ng-show because that seems to rectify the issue, but we are using nested ng-repeat directives so I'm not sure if that will work. Here is the general idea of what is going on:
<div ng-repeat="InventoryItemSubCategory in vmProduct.products | filter: ($scope.selectedGroup !== 'All' || '') && $scope.selectedGroup | filter:$scope.query | groupBy:'InventoryItemSubCategory':'productsByCategory' track by $index">
<h2>{{InventoryItemSubCategory.InventoryItemSubCategory}}</h2>
<md-card class="product-card" ng-repeat="product in InventoryItemSubCategory.items track by $index" md-theme="default" md-theme-watch>
<md-card-content>
<div class="media">
...
The idea is that each tab (group) has multiple subgroups which each have multiple items. The problem is, if I try to use an ng-show on the top level ng-repeat, it does not filter the array like the filter does so the inner ng-repeat elements do not display correctly.
So my question is, is that indeed the issue I'm running into? And if so, is there a clean way to use ng-show but also filter a parent array so it can be appropriately used by a child ng-repeat?
Thanks in advance!

Dynamically set item from <select> menu based on $state.params

I'm developing a feature where a user can repost a previously submitted 'project', which involves passing the data from the current project to $scope.params.project, archiving the existing project, and redirecting to the PostProject page where the user can resubmit the project, adjusting details in the form as needed.
The idea is that the PostProject form should be populated with the Job data from $scope.params so the user doesn't have to fill all of this out again.
I've successfully used this to populate a regular <input> field, so I know the data is being passed. I'm having trouble finding documentation on how to do this with a <select> dropdown menu, however. Everything I find tells me to use ng-model to be able to set the <select> menu to a default value.
However, I need to set the menu to a value based on $scope.params and have that value set the model for when the form is submitted. I'm stumped.
Here's the HTML. Assuming that $state.params.project is the intended JS object and that $state.params.project.service_type is a string that exists in the postOppCtrl.services array, I think this is all that is needed to demonstrate the problem.
From the HTML:
<select ng-if="$state.params.project"
ng-model="postOppCtrl.postOppProjForm.service_type"
ng-options="category as category for category in postOppCtrl.services"
// this part doesn't work, and I'm not sure what else to try.
ng-value="$state.params.project.service_type"
</select>
You could try using ng-init in the select tag to initialize the value:
ng-init="postOppCtrl.postOppProjForm.service_type = $state.params.project.service_type
I solved this by setting the model from my controller using $scope.
In my PostOpportunityController I had:
vm.postOppProjForm = {};
I replaced that with:
vm.postOppProjForm = { service_type: $state.params.project.service_type };

Understanding two-way data binding tutorial in AngularJS official site

I am looking at the official tutorial on AngularJS website that explains two-way data binding.
https://docs.angularjs.org/tutorial/step_04
The tutorial mentions this:
Angular creates a two way data-binding between the select element and
the orderProp model. orderProp is then used as the input for the
orderBy filter.
However, when looking at the live demo I only see one-way binding.
Can anybody explain how that demo is supposed to illustrate two-way data binding?
The tutorial has this explanation (emphasis mine):
This is a good time to talk about two-way data-binding. Notice that when the app is loaded in the browser, "Newest" is selected in the drop down menu. This is because we set orderProp to 'age' in the controller. So the binding works in the direction from our model to the UI. Now if you select "Alphabetically" in the drop down menu, the model will be updated as well and the phones will be reordered. That is the data-binding doing its job in the opposite direction — from the UI to the model.
So this is the demonstration of two-way binding. Although not very obvious.
Well, what you see is the binding from the view to the model (you write something in the input box and the view changes).
The other way round binding (from the model to the view) is the 'standard' javascript binding: you set a value in a scope variable (linked by Angular to a DOM element), and the view reflects it...
I agree with #Sergio Tulentsev it's not so obvious... :-)
//ng-model="query" is two way data binding of input to model property query
// any change in model will reflect inside input textbox and vice versa
Search: <input ng-model="query">
//ng-model="orderProp" will assign selected option to model property orderProp
Sort by:
<select ng-model="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select>
<ul class="phones">
//filter:query will filter phones having its property matching words to query and result will be ordered by orderProp that is by name or age
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp">
<span>{{phone.name}}</span>
<p>{{phone.snippet}}</p>
</li>
</ul>

Angular populate ng-repeat and ng-model

In my app I have a widget that is used on multiple pages and the selections made on the widgets are to be transferred between pages. So if I select something in the widget on the homepage and click 'continue' which then takes me to a new page, the widget should be pre-populated with the selections made on the homepage.
My widget follows the following format (although not exact for simplistic explanations):
<li ng-repeat="device in devices track by $index">
<select name="model[{{$index}}]" ng-model="selectedManufacturer" ng-options"...">
<select name="model[{{$index}}]" ng-model="selectedModel" ng-options"...">
</li>
It's the values of the ng-models inside the repeat statement that contain the key data in the widget that needs to be transferrable.
The number of devices needs to be transferrable too but that will be easy as devices is just an array of numbers so selectedModel.length -1 will equal the value of devices on the secondary pages.
Is it possible to pre-populate the values of ng-models?
Yes, you can prepopulate values of ng-models (or any scope variable) using ng-init
If you want to pre-populate the value in your ng-model which would mean a default/inital value in your drop-down. This can be achieved by doing the following:-
$scope.selectedManufacturer = listOfManufacturer[0];
$scope.selectedModel = listOfSelectedModel[0];

Categories