Show a dropdown based on proper selected radio button - javascript

Question:
How do I show all radio buttons but only one dropdown. This shown dropdown is one that reflects the currently selected radiobtn?
Live Code
Html:
<form ng-app="app" ng-controller="Ctrl">
<div class="color-pick" ng-repeat="(key, val) in productData.colors_and_sizes.data">
<input type="radio" name="colors" ng-model="myColor" ng-value="{{key}}" />{{key}}
<div class="size-pick">
<select ng-model="mySize" ng-options="size for size in val.sizes.split(',')"></select>
</div>
</div>
</form>
javascript:
var app = angular.module("app", []);
app.controller('Ctrl', function ($scope, $filter, $http) {
$scope.productData = {
"colors_and_sizes": {
"data": {
"Black": {
"sizes": "X Small, Small, Medium, Large, Xlarge, XX Large"
},
"Blue": {
"sizes": "X Small, Small, Medium, Large, Xlarge, XX Large"
}
}
}
};
});

Use the ng-hide or show directive on the div wrapping the select statement. The problem you're probably running into is that each ng-repeat iteration creates it's own scope, this means that each ng-model you create is completely independent.
You can see this here: http://jsfiddle.net/v2r9y6x2/, when each select radio is clicked it prints a different value underneath itself, in both cases this is the value of ng-Model being set:
You can fix this by referring to the parent scope with $parent.property instead of just the property name. This will assign the value to the parent controllers scope and work as you expect.
http://jsfiddle.net/djwruftr/
<form ng-app="app" ng-controller="Ctrl">
<div class="color-pick" ng-repeat="(key, val) in productData.colors_and_sizes.data">
<input type="radio" name="colors" ng-model="$parent.myColor" ng-value="key" />{{key}}
<div class="size-pick" ng-show="$parent.myColor==key">
<select ng-model="$parent.mySize" ng-options="size for size in val.sizes.split(',')"></select>
</div>
</div>
myColor: {{myColor}}<br/>
mySize: {{mySize}}
</form>

Related

using ng-options within ng-repeat

I am new to angular and I'm confused over this thing. I'm trying to populate a select box based on object inside an array. I want selectbox by using ng-repeat for that array... but initially i need to show only one selectbox after clicking add() next selectbox has to come. for ref:[initially one selectbox has to come]
HTML
<div class="col-lg-12" id="variant1" style="margin-top:10px" ng-repeat="variant in variants">
<div class="col-lg-4" style="text-align:right;padding-top:2px;padding-right: 20px" >
<label for="variant1name">Variant Name</label>
</div>
<div class="col-lg-6" >
<div >
<select class="form-control" ng-model="filterFormInputs.apps" ng-options="app.Application for app in variants" >
<option value="" disabled selected>Select an Application</option>
</select>
<label ng-repeat="checkbox in filterFormInputs.apps.details">
<input class="ecomtexttype1" type="checkbox" ng-model="checkbox.checked"> {{checkbox.name}}
</label>
</div>
</div>
</div>
Controller:
$scope.variants =
[
{"Application": "Color", "details":[{"name":"red"},{"name":"blue"},{"name":"black"}]},
{"Application": "Color", "details":[{"name":"red"},{"name":"blue"},{"name":"black"}]},
{"Application": "Color", "details":[{"name":"red"},{"name":"blue"},{"name":"black"}]}
]
I think that you can just have your add() function update the array... if things are configured correctly the new row should render due to the binding on the array.
As mentioned in comments you did not provide enough source code, so here is the assumed pseudo-code:
in html you might have
<button ng-click="$scope.add()">Add</button>
so in the controller
$scope.variants = [
// array of whatever you are displaying
{"foo":"bar1"},
{"foo":"bar2"}
];
$scope.add = function() {
variants.push({"foo":"bar_new"});
}
Have you considered using a Directive for this? That may work better, depending on your situation. Look into this: https://docs.angularjs.org/guide/directive

Parameterizing the data model in an Angular directive

I am implementing a control/widget that has three options, only one of which may be selected, which led me to using radiobuttons. This widget has to appear several times on various forms so I embarked on creating (incrementally) a dedicated directive.
The template of the directive is as follows:
<div class="row">
<span class="fieldlabel col-xs-3">{{title}}</span>
<div>
<label>
<input type="radio" data-ng-model="modelName" value="{{value1}}">
{{label1}}
</label>
<label>
<input type="radio" data-ng-model="modelName" value="{{value2}}">
{{label2}}
</label>
<label>
<input type="radio" data-ng-model="modelName" value="{{value3}}">
{{label3}}
</label>
</div>
The title, labels and values are correctly defined/computed either through using the custom directives or in the controller.
The last question I am facing now is how to specify different model bindings for each such widget? All instances of this widget currently share their model binding, which is of course not what I need. For instance, both of the divs in the fictitious example below would bind to "modelName" but I need them to bind to say "annotationsPos" and "menuPos" in the view's controller.
<div my-3option-radiobutton title="Show annotations"></div>
<div my-3option-radiobutton title="Menu position"></div>
How can I specify bindings in a custom directive?
EDIT 1
I think either I haven't really made myself clear or I lack some elements that would have helped me understand the answers that were offered.
If I had written the HTML by hand, I would have had something like this:
<div class="row">
<span class="fieldlabel col-xs-3">Position of your annotations</span>
<div>
<label>
<input type="radio" data-ng-model="annotationsPos" value="left">
Left of the element
</label>
<label>
<input type="radio" data-ng-model="annotationsPos" value="middle">
Through the element
</label>
<label>
<input type="radio" data-ng-model="annotationsPos" value="right">
Right of the element
</label>
</div>
<!-- -->
<div class="row">
<span class="fieldlabel col-xs-3">Position of the top menu</span>
<div>
<label>
<input type="radio" data-ng-model="menuPos" value="left">
Top left
</label>
<label>
<input type="radio" data-ng-model="menuPos" value="middle">
Top middle
</label>
<label>
<input type="radio" data-ng-model="menuPos" value="right">
Top right
</label>
</div>
<!-- -->
<div class="row">
<span class="fieldlabel col-xs-3">Position of notifications</span>
<div>
<label>
<input type="radio" data-ng-model="notificationPos" value="left">
Bottom left
</label>
<label>
<input type="radio" data-ng-model="notificationPos" value="middle">
Bottom middle
</label>
<label>
<input type="radio" data-ng-model="notificationPos" value="right">
Bottom right
</label>
</div>
Instead of copying and pasting this boilerplate code multiple times, I'm looking to do this thanks to an attribute directive:
<div my-3option-radiobutton title="Position of your annotations"></div>
<div my-3option-radiobutton title="Position of system notifications"></div>
<div my-3option-radiobutton title="Position of the top menu"></div>
What changes between these block is made of titles, values and, most importantly, model attribute values. I've covered the titles and values in the directive's controller in a non elegant way (see plunk further below). My problem is that I can't seem to:
determine where to specify an ng-model AND
have the "generated" HTML code refer correctly to that model attribute value (i.e. 'annotationPos', 'notificationsPos' and 'menuPos') AND
have two-way binding with the parent controller
EDIT 2
This plunk shows that #Suresh's answer is working, with a minor modification concerning the field name. However, the directive that I have written does not work (all widgets on the page bind to the same value), maybe due to it being an attribute directive and not an element directive. I don't want to have the latter type as it doesn't make sense to me and to top it all, this is to be integrated in an existing larger project, with other developers on it, that uses no element directive. This however does not mean that element directives are never to be used on the project.
Anyway, I'll keep looking for a solution. Thanks.
EDIT 3
I have resorted to using an ng-repeat directive in the template, just like #Suresh did. Using a developed template (i.e. repeating the input tag manually) does not work but I don't know whether that has to do with using/not using ng-repeat or rather with the way I "build" the values and labels in the controller.
Lessons learned from my plunk: even with a two-way binding over ngModel (below) in the controller of the widget:
all controls on the page will bind to the same value/variable unless ng-repeat is used
the parent controller's bound model is not updated if the template has data-ng-model="ngModel" instead of data-ng-model="$parent.ngModel"
scope: {
ngModel: "="
}
'use strict';
var app = angular.module('MyApp',[]);
app.directive("myRadiobutton", function () {
var templateHtml = function () {
return '<div class="form-group" >' +
'<label style="margin-right: 10px"; ng-repeat="(key, option) in options.valueList">' +
'<input type="radio" name="myfield" ng-value="option.value" ng-model="$parent.ngModel" ng-required="options.required" />{{option.title}}' +
'</label>' +
'</div>';
};
return {
scope: { options: '=', ngModel: '=' },
required: ['ngModel'],
restrict: 'E',
template: templateHtml,
};
});
app.controller('myController', function ($scope) {
$scope.radioGender = {
"label": "Gender",
"required": true,
"className": "",
"valueList": [
{
"title": "Male",
"value": "1"
},
{
"title": "Female",
"value": "2"
},
{
"title": "Others",
"value": "3"
}
]
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="MyApp" ng-controller="myController" >
<my-radiobutton options="radioGender" ng-model="genderValue"></my-radiobutton>
<span>{{genderValue}}</span>
</div>
You should use the "=" in the directive scope to bind an object:
directives.directive("dirname", function () {
return {
restrict: 'A',
replace: false,
scope: {
model: '=', // pass a referecne object
title: '#' // path as string
},
controller: function ($scope, $rootScope) {
...
},
}
});
<div dirname title="Menu Position" model="modelName" ></div>

Angular checkboxes disapear on select

I have a list of checkboxes in my app:
<div class="col-md-6" ng-repeat="item in segment.items">
<div class="checkbox">
<label>
<input
type="checkbox"
ng-model="item"
ng-checked="item.enabled"
value="{{item.id}}"
class="segment-visibility-checkbox"
/>
{{item.name}} <code>/ {{item.slug}}</code>
</label>
</div>
</div>
The data, that exists on the $scope as segment.items, looks something like this:
[
{"id":1,"slug":"nl","name":"Dutch","enabled":true},
{"id":4,"slug":"en","name":"English","enabled":false},
{"id":2,"slug":"fr","name":"French","enabled":true},
{"id":3,"slug":"de","name":"German","enabled":false}
]
This renders fine on load, and the correct checboxes are checked. However, if I select a checkbox, the label disappears and the binding appears to be lost. If I deselect a checkbox, it seems to work fine, but if I select it again, it disappears as well. No errors show up in the console.
This is what it looks like on load:
And as soon as I click on "English" I get this
I'm new to Angular so I suspect I am doing something obvious wrong. Can anybody please point me in the right direction?
pointing your ng-model to ng-model="item" will cast your item into a boolean.
Also, you should not use ng-model with ng-checked : https://docs.angularjs.org/api/ng/directive/ngChecked
what you should do is the following :
<input
type="checkbox"
ng-model="item.enabled"
value="{{item.id}}"
class="segment-visibility-checkbox"
/>
You need to bind the ng-model directly on your enabled boolean attribute:
<input
type="checkbox"
ng-model="item.enabled"
value="{{item.id}}"
class="segment-visibility-checkbox"
/>
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope) {
$scope.segment = {
items: [
{"id":1,"slug":"nl","name":"Dutch","enabled":true},
{"id":4,"slug":"en","name":"English","enabled":false},
{"id":2,"slug":"fr","name":"French","enabled":true},
{"id":3,"slug":"de","name":"German","enabled":false}
]
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
{{segment.items}}
<div class="col-md-6" ng-repeat="item in segment.items">
<div class="checkbox">
<label>
<input
type="checkbox"
ng-model="item.enabled"
value="{{item.id}}"
class="segment-visibility-checkbox"
/>
{{item.name}} <code>/ {{item.slug}}</code>
</label>
</div>
</div>
</div>

ng-click on image to check a radiobox

Question
How do I make the appropriate drop down visible when I click on the image or the checkbox.
In the end the radiobox will be hidden.
Currently the radio button does get checked but it does make the options appear properly? I think it's a scoping issue.
live code
I have a collection of colors and sizes:
app.controller('Ctrl', function ($scope, $filter, $http) {
$scope.productData = {
"colors_and_sizes": {
"data": {
"Black": {
"swatch_image": 'http://lorempixel.com/50/50',
"sizes": "X Small, Small, Medium, Large, Xlarge, XX Large"
},
"Blue": {
"swatch_image": 'http://lorempixel.com/50/50',
"sizes": "X Small, Small, Medium, Large, Xlarge, XX Large"
}
}
}
};
});
HTML: here is my form
<form ng-app="app" ng-controller="Ctrl">
<div class="color-pick" ng-repeat="(key, val) in productData.colors_and_sizes.data">
<input type="radio" ng-checked="selected" name="colors" ng-model="$parent.myColor" ng-value="key" />
<img ng-click="selected = true" ng-src="{{val.swatch_image}}" alt="">{{key}}
<div class="size-pick" ng-show="$parent.myColor==key">
<select ng-model="$parent.mySize" ng-options="size for size in val.sizes.split(',')"></select>
</div>
</div>
myColor: {{myColor}}<br/>
mySize: {{mySize}}
</form>
Currently, you defined $parent.myColor in order to save a value of the radio button. So if you want to be able to show the drop down based on the selected image, you can use ng-click on the img tag, as you already did, and assign the new value to it.
<form ng-app="app" ng-controller="Ctrl">
<div class="color-pick" ng-repeat="(key, val) in productData.colors_and_sizes.data">
<input type="radio" name="colors" ng-model="$parent.myColor" ng-value="key" />
<img ng-click="$parent.myColor = key" ng-src="{{val.swatch_image}}" alt="">{{key}}
<div class="size-pick" ng-show="$parent.myColor==key">
<select ng-model="$parent.mySize" ng-options="size for size in val.sizes.split(',')"></select>
</div>
</div>
myColor: {{myColor}}<br/>
mySize: {{mySize}}
</form>
Try it yourself.

Angular: radiobuttons stop firing "ng-change" after each one was clicked

I am building radio buttons dynamically. ng-change='newValue(value) stops being called after each radio button has been pressed once.
this works: Clicking on the radio buttons changes the value to foo/bar/baz.
http://jsfiddle.net/ZPcSe/19/
<div ng-controller="MyCtrl">
<input type="radio" ng-model="value" value="foo" ng-change='newValue(value)'>
<input type="radio" ng-model="value" value="bar" ng-change='newValue(value)'>
<input type="radio" ng-model="value" value="baz" ng-change='newValue(value)'>
<hr>
{{value}}
</div>
this code does not: The {{value}} - "label" is not updated once each radio button has been pressed at least once. Aparently ng-change is not fired any more.
<div ng-controller="MyCtrl">
<span ng-repeat="i in [0, 1, 2]">
<input name="asdf" type="radio" ng-model="value" value={{i}} ng-change='newValue(value)'>
</span>
{{value}}
</div>
http://jsfiddle.net/ZPcSe/18/
The Controlles is the same each time:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.value = '-';
$scope.newValue = function(value) {
$scope.value = value;
}
}
Thanks for your help.
ngRepeat creates new scope, so trying to set value sets it on the new scope. The workaround is to reference a property on an object that is on the parent scope--the object lookup happens on the parent scope, and then changing the property works as expected:
HTML:
<div ng-controller="MyCtrl">
<span ng-repeat="i in [0, 1, 2]">
<input name="asdf" ng-model="options.value" value="{{i}}" type="radio">
</span>
{{options.value}}
JS:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.options = {
value: '-'
};
$scope.newValue = function(value) {
// $scope.options.value = value; // not needed, unless you want to do more work on a change
}
}​
You can check out a working fiddle of this workaround. See angular/angular.js#1100 on GitHub for more information.
Just a quick work-around, we can achieve the same- using ng-model="$parent.value", because it would refer to the parent of ng-repeat scope i.e- in myCtrl scope
Only Change in ng-model-
<input name="asdf" type="radio" ng-model="$parent.value" value={{i}} ng-change='newValue(value)'>
Here is the fiddle
Try ng-click instead of ng-change.

Categories