Been searching all over Stackoverflow and there is loads of tips on how to remove the 'dreaded' empty (undefined) options element in a select dropdown. However I have yet to find an answer for when my code looks like this:
--VIEW--
<form class="simple-mods">
<fieldset ng-repeat="modifier in modifiers">
<label for="{{ modifier.id }}">{{ modifier.title }}</label>
<select name="" id="{{ modifier.id }}" ng-model="mods[modifier.id]" name="modifier[{{ modifier.id }}]" ng-mod="{{ modifier.title }}">
<option value="{{ variation.id }}" ng-repeat="variation in modifier.variations">{{ variation.title }}</option>
</select>
</fieldset>
<fieldset>
<button ng-click="addCart()" ng-if="!addStatus" class="btn btn-success" translate>Add to cart</button>
<button ng-if="addStatus" class="btn btn-warning" ng-bind-html="addStatus">{{ addStatus }}</button>
</fieldset>
</form>
-- CONTROLLER --
.controller('ProductCtrl', function ($scope, $rootScope, moltin, $timeout, product) {
var productId = product.id,
qty = 1,
mods = {};
$scope.product = product;
$scope.addStatus = null;
$scope.modifiers = product.modifiers;
});
If any one can help I would be very grateful.
#BETTY it doesnt seem to work. I have attached 2 screenshots
Screen shot 3
Screen shot 4 (Value is now a string)
#betty
<fieldset ng-repeat="modifier in modifiers" ng-init="mod[modifier.id] = modifier.variations[0].id">
<label for="{{ modifier.id }}">{{ modifier.title }}</label>
<select id="{{ modifier.id }}" ng-model="mods[modifier.id]" ng-options="variation.id as variation.title for variation in modifier.variations">
<option></option>
</select>
</fieldset>
Try to clean up modifier.variations in your controller, deleting undefined elements from modifier.variations
$scope.modifier.variations = $scope.modifier.variations.filter(function(n){ return n != undefined });
You need to inject $scope in your controller.
You need to set the ng-model right (=> mods[modifier.id]), either by using ng-init or setting it in the controller..
This solution uses ng-init which sets the default value to the first variation ID. I also removed everything you don't need and used ng-options (reduces some HTML ;)).
<fieldset ng-repeat="modifier in modifiers" ng-init="mods[modifier.id]=modifier.variations[0].id">
<label for="{{ modifier.id }}">{{ modifier.title }}</label>
<select id="{{ modifier.id }}" ng-model="mods[modifier.id]" ng-options="variation.id as variation.title for variation in modifier.variations">
<option></option>
</select>
</fieldset>
I also recommend adding an empty option-tag, here is why: ng-model is getting wrong value from dropdown
AND you need $scope.mods = {}; in the controller instead of var mods = {}; because you are using mods in the HTML!
Maybe you also need to use track by variation.id so that the selected value can be checked right (ng-model and option value). I answered a similar question and track by was the answer, see https://stackoverflow.com/a/32999399/595152 ;)
Related
I'm not sure if this is going to make sense, I spent some time trying to research the answer I require.
I'm wanting to know if it is possible in angular to change the URL requested from a $http.get request from a value of a select box.
So I have built a simple controller which gets a JSON file and passes the response in to the scope, then I pass that data in to the view.
But I will have several JSON files which I want to load on selection of an option from a drop down and reload the data.
My Angular is fairly basic, so i'm unsure if this is at all possible to do on the fly?
var app = angular.module('serverstats', []);
app.controller('ServerController', function($scope, $http){
var apiFeed = $('.apiSelecter').val();
$http.get(apiFeed).then(function(response){
$scope.status = response.data;
$scope.server = [];
angular.forEach($scope.status.servers, function(svr) {
$scope.server.push(svr);
})
console.log('server', $scope.server);
});
});
<select class="apiSelecter">
<option value="/test.json">Data File 1</option>
<option value="/test1.json">Data File 2</option>
<option value="/test2.json">Data File 3</option>
</select>
<div ng-controller="ServerController" id="server-stats" class="server-stats">
<div ng-repeat="stat in server" class="container" ng-cloak>
<div class="stats-box col-md-2">
<p class="lead">Server Name: {{ stat.serverName }}</p>
</div>
<div class="stats-box col-md-2">
<p class="lead">Response Time: {{ stat.responseTime }}</p>
</div>
<div class="stats-box col-md-2">
<ul>
<p class="lead">Ports</p>
<li><p class="lead">{{ stat.ports.port1 }}</p></li>
<li><p class="lead">{{ stat.ports.port2 }}</p></li>
<li><p class="lead">{{ stat.ports.port3 }}</p></li>
<li><p class="lead">{{ stat.ports.port4 }}</p></li>
<li><p class="lead">{{ stat.ports.port5 }}</p></li>
</ul>
</div>
Apologies now included code
Of course you can.
HTML :
<select id="mySelect" ng-model="myValue" ng-change="myMethod()">
<option ng-repeat="o in options" value="{{o.url}}">{{o.label}}</option>
</select>
And in your controller
$scope.options = [
{url : 'www.google.com', label: 'google'},
{url : 'www.facebook.com', label:'facebook'}
]
$scope.myMethod = function() {
console.log($scope.myValue);
//HTTP Resquest here
}
The ng-change attribute will trigger when you change the selected option. The ng-model allows you to store the current value in memory.
After your HTTP request (in then .then) you can load your JSON and all the stuff you do.
NB : if your select is a Materialize one, use the angular-materialize library and use
<select id="mySelect" ng-model="myValue" ng-change="myMethod()">
<option ng-repeat="o in option" value="{{o.url}}" material-select watch>{{o.label}}</option>
</select>
I have a dropdown where items are populated from $scope.role. Now I need to remove the values from $scope.role once the value is added or selected in dropdown. I did splice(index,1) which actually delete the first element only. Need assistance.
$scope.role = ['Actor', 'Director/ Asst. director', 'Lyricist',
'Music director/ Asst. director', 'Singer', 'Standup Comedian', 'Model',
'Cinematographer', 'Photographer', 'Script Writer', 'Choreographer',
'Editor/ Promo editor', 'Costume designer', 'Art director', 'Stunt artist',
'Voice-over artist', 'Graphic Designer', 'Screenplay', 'Dialogue',
'Back ground music'];
Html:
<div class="row newRow">
<div class="form-group fields col-sm-2 col-xs-4">
<label>ROLE *</label>
<select name="role" class="form-control1 drop2" required ng-model="model.role" placeholder="select">
<option value='' disabled selected>Select</option>
<option ng-repeat="item in role track by $index" value="{{item}}">{{item}}</option>
</select>
</div>
<div class="form-group col-sm-2 col-xs-4">
<button ng-click="AddRole()">Click to Add Role</button>
</div>
</div>
JS:
$scope.multiRoles = [];
$scope.role == $scope.dummy;
$scope.rolesAdded = false;
$scope.AddRole = function(index) {
debugger;
if ($scope.model.role !== undefined) {
$scope.multiRoles.push($scope.model.role);
$scope.role.splice(index, 1);
console.log($scope.role);
}
};
You can do it in two ways 1) As suggested by #nikjohn by sending your $index of dropdown in ng-click = "AddRole($index)" and then splice or else
2) You can find the index of the selected option by using the ng-model binded to the dropdown.
$scope.AddRole = function(){
debugger;
if($scope.model.role !== undefined ){
$scope.multiRoles.push($scope.model.role);
var index = $scope.role.indexOf($scope.model.role); //just find the right index which is the selected option in dropdown.
$scope.role.splice(index,1);
console.log($scope.role);
}
};
In your HTML, pass $index to the AddRole. Otherwise, the function does not know what $index is, and also include the button within the ng-repeat:
<select name="role"
class="form-control1 drop2" required
ng-model="model.role" placeholder="select">
<option value='' disabled selected>Select</option>
<option ng-repeat="item in role track by $index" value="{{item}}"> {{item}}
<button ng-click = "AddRole($index)">Click to Add Role</button>
</option>
</select>
In your Controller, there's an extra = that I've highlighted in my comment:
$scope.multiRoles = [];
$scope.role == $scope.dummy; // Why a `==` here? This should be a `=`
$scope.rolesAdded = false;
$scope.AddRole = function(index){
debugger;
if($scope.model.role.length){ // Cleaner method to verify that the array is non-empty
$scope.multiRoles.push($scope.model.role);
$scope.role.splice(index,1);
console.log($scope.role);
}
};
May I also suggest that you use Angular's select implementation with ng-options because:
Choosing between ngRepeat and ngOptions
In many cases, ngRepeat can be used on elements instead of ngOptions to achieve a similar result. However, ngOptions provides some benefits:
more flexibility in how the <select>'s model is assigned via the select as part of the comprehension expression
reduced memory consumption by not creating a new scope for each repeated instance
increased render speed by creating the options in a documentFragment instead of individually
Specifically, select with repeated options slows down significantly starting at 2000 options in Chrome and Internet Explorer / Edge.
I have a very interesting problem. Have 2 drop-downs, with options
0 = Exclude, 1 = Include, 3 = Only
When user want to select 3 from these 2 list, the other one should be changed to 0-Exclude. But when I try this code, its calling each other and in result the selected (3-Only) dropdown shows 0-Exclude and other 3-Only which is reverse.
Here is the code
Controller.js
$scope.lockedChanged = function() {
if ($scope.data.lockedGldata == 2) {
$scope.data.deactivatedGldata = 0;
}
};
$scope.deactivatedChanged = function () {
if ($scope.data.deactivatedGldata == 2) {
$scope.data.lockedGldata = 0;
}
};
View.html
<div class="form-group">
<label for="lockedGlOption" class="col-sm-3 control-label">Locked G/L:</label>
<div class="col-sm-3">
<select class="form-control" required ng-init="data.deactivatedGldata = 0"
id="lockedGlOption"
ng-model="data.deactivatedGldata"
ng-options="o.id as o.text for o in lockedGlOptions"
ng-change="lockedChanged()">
<option value="" disabled>Select an option...</option>
</select>
</div>
</div>
<div class="form-group">
<label for="DeactivatedGlOption" class="col-sm-3 control-label">Deactivated G/L:</label>
<div class="col-sm-3">
<select class="form-control" required ng-init="data.lockedGldata = 0"
id="DeactivatedGlOption"
ng-model="data.lockedGldata"
ng-options="o.id as o.text for o in DeactivatedGlOptions"
ng-change="deactivatedChanged()">
<option value="" disabled>Select an option...</option>
</select>
</div>
</div>
I think, that when you click on first select. It listen to change of model deactivatedGlData, and in lockedChanged function, which is assigned to ng-change of this dropdown, there is mismatch.
It listen to another dropdown, instead of self one, and that's why it's presenting in reverse.
Could you try to switch order of ng-change?
Instead of in two dropdowns in order:
ng-change="lockedChanged()">
ng-change="deactivatedChanged()">
Write:
ng-change="deactivatedChanged()">
ng-change="lockedChanged()">
I have 2 drop down lists using ui-select2
<label class="control-label" for="MakeSelect">Make </label>
<select class="form-control col-md-2" id="MakeSelect" name="make" ui-select2
ng-model="carDetails.make">
<option ng-if="!carDetails.make" value="">[SELECT]</option>
<option ng-repeat="make in makes" value="{{ make }}">{{ make}}</option>
</select>
</div>
<div class="col-md-5">
<label class="control-label" for="ModelSelect">Model </label>
<select class="form-control col-md-2" id="ModelSelect" name="make" ui-select2
ng-model="carDetails.model">
<option ng-repeat="model in models" value="{{ model }}">{{ make}}</option>
</select>
After I choose a value in the drop down list "Makes" I am activating a watch that inside it I load the content of "Models" Dropdown lists.
Then, In order to refresh the drop down lists content in the GUI I call $scope.$digest() :
$scope.$watch('carDetails.make', function (make) {
console.log('selected make is: ' + make);
if (make == "") {
return;
}
Parse.Cloud.run('getCarModels', {'Make': make}, {
success: function (results) {
$scope.parseModels = results.resultSet;
$scope.models = results.distinctModels;
$scope.$digest();
},
error: function () {
console.log("Error: Failed to load models");
console.log(Parse.Error);
}
});
The problem is that with $digest the selected value of the first drop down list is becoming null and without it just doesn't refresh the view.
Any suggestions please?
They're both pointing to the same scope model, carDetails.make. So, of course, the first will become null, because the second drop down list sets carDetails.make to null. Also, I don't think you need to use digest, although, you should be using $scope.$apply. But, angularjs should run the digest anyway.
I have a object called list in my JS file:
$scope.list = {
hospital : 'Hospital',
clinic : 'Clinic',
gp : 'GP',
denist : 'Dentist',
aae : 'A&E'
};
I'm printing these five facilities to the form like so:
<form role="form" name="addPlaceForm" ng-submit="createHospital(newHospital)">
<label class="checkbox-inline" ng-repeat="(key, value) in list">
<input type="checkbox" id="{{ key }}" value="{{ key }}" ng-model="newHospital.facilities">{{ value }}
</label>
</form>
When I submit my form, I'd like it to send the the result of the checked checkboxes to my facilities object in Firebase. My createHospital function looks like this:
var rootRef = new Firebase('URL');
var placesRef = rootRef.child('places');
function createHospital(hospital) {
placesRef.push(hospital);
}
How can I push only the checked checkboxes to an nested object called facilities which sits inside my places object that's currently in my Firebase?
Any help with this is appreciated. Thanks in advance!
I made a plunker to demonstrate how to do this at http://plnkr.co/kfH4I5Fzy2Ma14FjQj67.
You were mostly right. The changes I made was making the ng-model="newHospital.facilities[key]" and initializing $scope.newHospital to {} so it is seen in the controller. I also added a submit button.
<form role="form" name="addPlaceForm" ng-submit="createHospital(newHospital)">
<label class="checkbox-inline" ng-repeat="(key, value) in list">
<input type="checkbox" id="{{ key }}" value="{{ key }}" ng-model="newHospital.facilities[key]">{{ value }}
</label>
</form>