Currently I'm stuck on a select input field. In the project was used this code:
<select ng-init="crtController.order.orders[$index].quantity = 0" ng-model="crtController.order.orders[$index].quantity" ng-options="value for value in crtController.quantity.values track by value" ng-change="crtController.quantity.check()"></select>
It was using this "quantity" variable:
this.quantity = {
values: [0,1,2,3,4,5,6,7,8,9,10],
decrease: function(index) {
if (vm.order.orders[index].quantity > 0) {
vm.order.orders[index].quantity--;
this.check();
}
},
increase: function(index) {
if (vm.order.orders[index].quantity < 10) {
vm.order.orders[index].quantity++;
this.check();
}
},
check: function() {
this.valid = false;
for (var i = 0; i < vm.order.orders.length; i++) {
if (vm.order.orders[i].quantity > 0) {
this.valid = true;
}
vm.order.orders[i].productId = vm.products[i].id;
}
vm.calculatePrice();
}
}
On the top of this select I've got a variable product.stock. Let's say this is 5. In that case I only want it to show 0,1,2,3,4,5 from the quantity array.
I already tried serveral things:
1. Adding a "where" clause. This didn't seem to work or I implemented it the wrong way of course.
2. Added a filter, not quite sure how this works using the value variable and the product.stock variable but I gave it a try.
3. I tried to change it so the repeat is on a option. This gave the possibility to "hide" options that should not be shown.
<select ng-init="crtController.order.orders[$index].quantity = 0" ng-model="crtController.order.orders[$index].quantity" ng-change="crtController.quantity.check()">
<option ng-repeat="value in crtController.quantity.values track by value" value="{{value}}" ng-hide="product.stock < value" ng-bind="value"></option>
</select>
but that didn't seem to work either as the first value of the selectbox is now empty. Beside that the buttons arround the select option:
<div class="input-group-addon hidden-xs"><a class="min" ng-click="crtController.quantity.decrease($index)">-</a></div>
didn't seem to work anymore. I also have visited a lot of similar Stackoverflow questions but still didn't find my solution. Questions such as:
AngularJs conditional display for ng-options: I don't have this in my array, but didn't work just on a check of two variable.
not sure that i understand question but try to change ng-hide by ng-if inside
or
<option ng-repeat="value in crtController.quantity.values|limitTo:product.stock track by $index" value="{{value}}" ng-if="product.stock >= value" ng-bind="value"></option>
You can try filtering the options
<option ng-repeat="value in crtController.quantity.values track by
value | filterQuantity " value="{{value}}" ng-bind="value"></option>
filters.filter('filterQuantity', function () {
return function(tasks, tags) {
return tasks.filter(function(value) {
...
});
};
});
just play around with this, i hope it helps
Related
How to make a select option not disappear when selected if filtered out and not be displayed on other select dropdowns.
For example
if i have some array of objects, and i make
<select ng-options = "here we go through each object "></select>
My idea is to make filter function that would not display any item that's in the array i'm filling if I selected this item before. So that would be my array of items that should be unavailable in another dropdowns. Is there some example way how can i accomplish that? I have an idea that my filter would look something like this:
for(var i=0;i<$scope.removedIds.length;i++){
if(tab.tabID===$scope.removedIds[i].tabID)
return false;
}
return tab;
and this would be used in ng-options for ex: ng-options="tab.ID as tab.name for tab in tables | filter: "
and in my function ng-change i would be adding to $scope.removedIds next values that should not be available in next select dropdowns. But I think it would not work because values would be filter out in different select dropdowns.
Example
I guess that you have three dropdowns with same datasource, a simple solution would look like:
<div>
<select ng-model="selectedItem1" ng-options="item1 for item1 in options1"></select>
<select ng-model="selectedItem2" ng-options="item2 for item2 in options2"></select>
<select ng-model="selectedItem3" ng-options="item3 for item3 in options3"></select>
</div>
In the corresponding controller, and using angularjs watchers, add these lines:
$scope.options1 = ["opt1","opt2","opt3"];
$scope.options2 = angular.copy($scope.options1);
$scope.options3 = angular.copy($scope.options1);
$scope.$watch("selectedItem1", function(nv, ov) {
if (nv != ov) {
$scope.options2.splice($scope.options2.indexOf(nv),1);
$scope.options3.splice($scope.options3.indexOf(nv),1);
}
});
$scope.$watch("selectedItem2", function(nv, ov) {
if (nv != ov) {
$scope.options1.splice($scope.options1.indexOf(nv),1);
$scope.options3.splice($scope.options3.indexOf(nv),1);
}
});
$scope.$watch("selectedItem3", function(nv, ov) {
if (nv != ov) {
$scope.options1.splice($scope.options1.indexOf(nv),1);
$scope.options2.splice($scope.options2.indexOf(nv),1);
}
});
Referring to this question
I am able to successfully apply filter for my table. Now I want to change the way this filter is working. Here is the situation:
I am applying Mapped filter. It filtered out all mapped variables for me. Now I will change the value of one of the filtered variables, as soon as I delete the complete value, the variable is moved to Unmapped list and User is not able to change the variable. User now need to change the filter to either All or UnMapped filter to edit that variable.
Same in the case of Unmapped filter. Select Unmapped filter, as soon as I try entering value, the variable disappears and moved to 'Mapped' list.
What I need to do is to apply filter only when I select filter from drop down using ng-change and when I try to edit some variable the filter should not work.
Here is the code:
For Filter :
$scope.filterOpt = 'All';
$scope.emptyOrNull = function (variable) {
if ($scope.filterOpt == "All")
return true;
if ($scope.filterOpt == "Mapped")
return variable.Name && variable.Variable
if ($scope.filterOpt == "UnMapped")
return !(variable.Variable) ;
}
HTML :
<select class="selectpicker form-control" ng-model="filterOpt" ng-change="emptyOrNull()">
<option value="All">All</option>
<option value="Mapped">Mapped</option>
<option value="UnMapped">Un-Mapped</option>
</select>
and Table:
<tr ng-repeat="var in Mappings | filter: searchVariable | filter : emptyOrNull">
<td>{{var.Name}}</td>
<td>
<div><input-dropdown name="fqn" ng-model="var.Variable" list="variables" ng-disabled="var.IsTrue"></input-dropdown></div>
</td>
</tr>
UI :
In above picture when I select Mapped from filter and try to change/delete Value1 it should not disappear.
Please help.
Basically I don't understand why do you want | filter : emptyOrNull, when you want to update UI only if you change the dropdown value.
Why don't you only update array($scope.Mappings). In this array you can only push values you want to display.
Remove filter and update your dropdown ng-change function like this
Here origArray is your original array, I am just changing scope variables
$scope.emptyOrNull = function (variable) {
$scope.Mappings = [];
if ($scope.filterOpt == "All") {
$scope.Mappings = angular.copy(origArray);
} else {
for (var i = 0; i < origArray.length; i++) {
if ($scope.filterOpt == "Mapped") {
if (origArray[i].Name && origArray[i].Variable) {
$scope.Mappings.push(origArray[i]);
}
}
if ($scope.filterOpt == "UnMapped") {
if (!origArray[i].Variable) {
$scope.Mappings.push(origArray[i]);
}
}
}
}
}
Don't use filter for this kind of requirements, it reduces performance.
What you can do is add a conditional filter. That means apply filter only when you want it to be and don't apply when you don't want.
you can check when input is focused with something like and toggle a variable to disable or enable filter
<input-dropdown name="fqn" ng-model="var.Variable" ng-focus="disable=true" list="variables" ng-disabled="var.IsTrue"></input-dropdown>
And to do conditional filtering use
<tr ng-repeat="var in Mappings | filter : (disable ? '' : emptyOrNull)">
And then you can update the disable to true on changing mapped/unmapped dropdown.
Hope this helps
My markup looks something like this
<select ng-model="search.parameters.selectedOptionId" ng-options="lookup.id as lookup.lookupValue for lookup in lookups.options" custom-attribute-directive>
<option value="" selected>All</option>
</select>
From the customAttributeDirective, I need to access the selected option value that is displayed in the dropdown (i.e. lookup.lookupValue). I've tried accessing the $viewValue on the ngModel, but it is set to the lookup.id (which I assume is the fault of the way ng-options is set up). I cannot modify the implementation of the markup due to the circumstances that I am implementing the directive against, so the problem must be solved there.
Bind the lookup.lookupValue for display and lookup.lookupValue for backend Id too. In that case you will get display text with ng-model
<select ng-model="search.parameters.selectedOptionId" ng-options="lookup.lookupValue as lookup.lookupValue for lookup in lookups.options" custom-attribute-directive>
<option value="" selected>All</option>
Found my answer. It turns out directives can access the dom directly.
link: function (scope, element, attrs, controller) {
scope.getViewValue = function () {
if (angular.isDefined(scope.overrideTagDisplay)) {
return scope.overrideTagDisplay;
}
else if (element[0].nodeName == "SELECT") {
return element.children()[element[0].selectedIndex].text;
}
else {
return ngModel.$viewValue;
}
}
scope.initialize()
}
EDIT: I found later that this method has the issue that if javascript modifies the model value somewhere else in the code and then this piece immediately runs, it does not pick up the new value because the DOM hasn't updated (this includes on page load and initial setting). I ended up passing the list of lookups into the directive as well and got around the lack of standardization in those lookups by having an optional "comparator key" that would defaultly look something like
var comparitorKey = { id: "id", lookupValue: "lookupValue"};
which is then utilized like this
var id = ngModel.$modelValue;
var filtered = scope.lookupList.filter(function (lookup) { return lookup[scope.comparitorKey.id] == id });
return filtered.length > 0 ? filtered[0][scope.comparitorKey.lookupValue] : null;
the idea being that someone could pass in an alternative like
var comparitorKey = {id: "userId", lookupValue: "userName" };
I have an angularjs app, which has a select filled with options from an arry, using ngOptions. Every time the user clicks the button to add one, the ngRepeat directive generates a new select at the bottom.
I want to make sure that the user cannot select duplicate values.
So if my list contains 3 items: Item1, Item2 and Item3, and the user selects Item3 and then presses the button, the last generated select list should contain only items 'Item1' and 'Item2'.
If the user would then select 'Item1' and presses the button, the user should see the next select be generated with only the 'Item2' option.
So generally, in the case above, the generated HTML should be something like this:
<div data-ng-repeat="item in selectedOptions">
<select>
<option value="1">Item1</option>
<option value="2">Item2</option>
<option value="3">Item3</option>
</select>
<select>
<option value="1">Item1</option>
<option value="2">Item2</option>
</select>
<select>
<option value="2">Item2</option>
</select>
</div>
Keep in mind: the user will keep seeing all THREE of the selects, once with every option available, once with just two options available, and once with just one option available.
I've been thinking of a lot of ways to make this work, but so far I haven't had any luck. Does anyone know of a pattern I can use in angular to achieve this behavior?
This is something that I've tried so far.
<div data-ng-repeat="function in item.Functions">
<select data-ng-model="function.Id" data-ng-options="j.Id as j.Name for j in getCorrectFunctions(functionsList)">
<option selected="selected" value="">---</option>
</select>
<a data-ng-click="addFunction()">
<i class="fa fa-plus fa-plus-lower"></i>
</a>
</div>
and in my directive code I have following function:
function getCorrectFunctions(functionList) {
var item = scope.item;
var list = functionList.slice();
//excluded for brevity: this was a loop which would remove every item that wasn't available anymore
return list;
}
I thought this would be executed once for every item in the list, but that does not seem to be case.
I don't think applying a filter would be any different, would it?
Here's one take on this. This does not have support for dynamically adding new functions, but however it does prevent user from selecting any given item twice.
See Plunker for working example and more details.
First the Angular setup part. Here I've defined a mock array of function objects ($scope.functions) and array for user made selections ($scope.selected)
var app = angular.module('app', []);
app.controller('SelectCtrl', function ($scope) {
$scope.functions = [
{id: 1, name: 'First'},
{id: 2, name: 'Second'},
{id: 3, name: 'Third'},
];
$scope.selected = [];
$scope.selectedFilter = function (selectNumber) {
// snipped for now
};
});
In html, showing only one select, but similar approach used for all 3 selects: set the selected value to the selected array in given index (0 for the case shown below), and use selectedFilter to filter functions with same index value.
<select ng-options="j.id as j.name for j in functions | filter:selectedFilter(0)" ng-model="selected[0]">
<option value="" selected="selected">---</option>
</select>
Then finally the filtering function. It returns true for all unselected functions and for the selected function of the given select.
$scope.selectedFilter = function (selectNumber) {
return function (func) {
if ($scope.selected.length === 0) {
return true;
} else {
var unselectedFunctions = _.filter($scope.functions, function (fn) {
return _.findIndex($scope.selected, function (sel) {
return fn.id === sel;
}) === -1;
});
var selectedForCurrentId = $scope.selected[selectNumber];
var selectedForCurrent = _.find($scope.functions, {id: selectedForCurrentId});
return func === selectedForCurrent || _.findIndex(unselectedFunctions, {id: func.id}) > -1;
}
};
};
Here I've used Lodash for some nice helper functions. Not affiliated with Lodash in any way, but I really suggest you to take a look at it, or any other similar library.
Hopefully this helps you to get things moving on!
Thank you in advance.
I am still learning JavaScript and as a project approached, really need some help/insight.
The logic that I am working on is this:
1. HTML structure:
<input title="Type Here" class="search" type="text" placeholder="Type Here">
<select id="device_select">
<option id=one value='a'>a</option>
<option id=two value='b'>b</option>
<option id=three value='c'>c</option>
<option id=many value='many'>many</option>
</select>
<span class="content-btn-1" type="button"></span>
2. JS structure:
$(function(){
var one = {title:"titletext", description:"descrtext", keyword:"text",
subject:"533,567,457", provider:"c9drlt-sdgtrzz", training:"true"};
var two = {title:"titletext", description:"descrtext", keyword:"textthis",
subject:"537", provider:"c9drlt-sdgtrjt", training:"false"};
});
3. JS logic structure:
function search_class() {
if (training == true) {training = "&tr=0";} else {training = "";}
return training;
}
function search_custom() {
// NOT SURE HOW TO PULL IT UP
// if subject has more than 1 variable like subject:"533,567,457"
// then construct the logic to separate them:
// &s=533&s=2&567&s=3&457
return subject;
}
var url = "www.website.com";
var text_area = $('.search');
var btn_click = $('.content-btn-1');
btn_click.click (function () {
var value = text_area.val();
var ty = "#s=";
if ($.trim($(text_area).val())) {
window.location.href = url+ty+search_class()+search_custom();
}
});
4. The outcome:
www.website.com#s=titletext&d=descrtext&t=text&p=c9drlt-sdgtrzz&tr=0&s=533&s=2&567&s=3&457
5. The hard part:
How can we do the logic so it takes that array in #2, attaches to the option id one, two ... etc in #1 and then constructs the link in #3 on click?
In nutshell: This is a search function with options that has unique variables.
Appreciate any help!
First off, I think you want to clean up your select box a bit, and give it values you can actually use in javascript.
<input title="Type Here" id="search_text" type="text" placeholder="Type Here" />
<select id="device_select">
<option value='1'>a</option>
<option value='2'>b</option>
<option value='3'>c</option>
<option value='0'>many</option>
</select>
<input id="submit_button" type="button" />
Then we need to clean up your object a bit so it's a) more readable, and b) it links to your select box nicely. If we nest it into one object, referencing it later will be easier.
// we would like an array that corresponds with our values in the select box.
var options = [
false,
{
title: "titletext",
description: "descrtext",
keyword: "text",
subject: "533,567,457",
provider: "c9drlt-sdgtrzz",
// a boolean like "false" or "true" should not be surrounded by braces, is easier to manipulate.
training: true
},{
title: "titletext",
description: "descrtext",
keyword: "textthis",
subject: "537",
provider: "c9drlt-sdgtrjt",
training: false
}
];
The final bit is in the logic. I've tried to streamline it a bit but the most important change is the for-loop in this case, as it will list every key/value pair and then we can add it to our search string. I Have also included some error dodging here, like checking if theres empty values and if the selected values actually exist (for example, if you select 3 in device_options, we don't have that index in our options array above, so we can't actually construct that - but it won't actually error out.)
$("#submit_button").on("click", function(event){
// now for the hard part, converting your select item into a string and appending the text
// 1. get the search string from the input
var searchstring = "#searchText=" + $("#search_text").val().trim();
// 2. get the select box value of the selected option
var selected = $("#device_select").val();
// 3. Get the corresponding value.
// If the corresponding value is false (remember the first item in the array above?), then we do nothing.
// We also do nothing if we are looking for an undefined number in the array (say, item #238)
selected = typeof options[selected] != "undefined" && options[selected] !== false
? options[selected]
: false;
// if selected was not set to false, then it exists in our options and we can use it.
if(selected){
for(key in selected){
// if you set a value in options to false, we'll ignore it here using a 'continue'
// continue will move on to the next iteration of the for loop immediately
if(!selected[key]) continue;
searchstring += "&" + key + "=" + selected[key];
}
window.location.href = "http://www.mysite.tld/" + searchstring;
} else {
// log an error here.
if(console) console.log("Could not find device!");
}
});
Does this make sense/help? I have not tested this myself, but it should all work.