How to display repeated drop down based on button selection in AngularJS - angularjs

I need to display a drop down along with Plus button at first time. Based on button click it should display one more combination , I mean same drop down with options excluded previous selected value which we have from the first drop down and the plus button. This action should be repeat based on plus button selection.
Here is my code:
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.init = function() {
$scope.display = false;
};
$scope.init();
$scope.records = [
{ id: "part1", part: "Frt Bumper Cover" },
{ id: "part2", part: "Frt Lwr Bumper Cover" },
{ id: "part3", part: "Frt Upr Bumper Cover" },
{ id: "part4", part: "Hood Panel" },
];
$scope.changedValue = function(key) {
// alert(key);
//var index = $scope.records.indexOf(item);
//alert(index);
$scope.records.splice(index, 1);
//delete $scope.records[key];
// alert(JSON.stringify($scope.records));
};
$scope.sample = function() {
$scope.display = true;
// alert("sample: "+$scope.display);
//alert("inside sample:::"+JSON.stringify($scope.records));
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl" ng-init="init()">
<div>
<select ng-model="selectedRecord"
ng-change="changedValue(selectedRecord)"
ng-options="record.id as record.part for record in records">
<option ng-repeat="x in records">{{x.part}}</option>
</select>
<input type="submit" value="+" ng-show="records.length!=1"
ng-click="sample()" />
</div>
<div ng-show="display">
<select ng-model="selectedRecord"
ng-change="changedValue(selectedRecord)"
ng-options="record.id as record.part for record in records">
</select>
<input type="submit" value="+" ng-show="records.length!=1"
ng-click="sample()" />
</div>
</body>
I am unable to display like that, please share your ideas to do this

My friend, i think i have a solution for your problem. :D
Its very basic code i think, so i would be happy to explain more in depth if needed.
look code here: plnkr, this is basically all the code, so its my first plunker.
$scope.originalRecords = [
{ id: "part1", part: "Frt Bumper Cover" },
{ id: "part2", part: "Frt Lwr Bumper Cover" },
{ id: "part3", part: "Frt Upr Bumper Cover" },
{ id: "part4", part: "Hood Panel" },
];
$scope.selectArray = [{selectedOption: null, options: $scope.originalRecords}];
$scope.selectedOption =[];
$scope.hideButton = false;
$scope.addNewSelect = function (arrayToSearch, selectedOption) {
var index = arrayToSearch.map(function(d) { return d['part'];}).indexOf(selectedOption);
var newRecords = arrayToSearch.slice();
newRecords.splice(index, 1);
if (newRecords.length > 0) {
$scope.selectArray.push({selectedOption: null, options: newRecords});
} else {
$scope.hideButton = true;
}
}
Hope it helps.

Related

How can I make square-connect work with angularjs?

Basing myself on the example provided by the SquareUp documentation (https://github.com/square/connect-api-examples.git). I am trying to integrate squareup to process payments with CC but I do not know what happens.
the view:
<div class="bg-light lter b-b wrapper-md">
<h1 class="m-n font-thin h3"></h1>
</div>
<div class="wrapper-md" >
<div class="row">
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-heading font-bold">CC info</div>
<div class="panel-body">
<div class="no-boot" ng-controller="PaymentController" ng-cloak>
<div id="successNotification" ng-show="isPaymentSuccess">
Card Charged Succesfully!!
</div>
<form novalidate id="payment-form" ng-hide="isPaymentSuccess">
<div id="card-errors" ng-repeat="error in card_errors">
<li>{{error.message}}</li>
</div>
<div>
<label>Card Number</label>
<div ng-model="data.card.card_number" id="sq-card-number"></div>
</div>
<div>
<label>CVV</label>
<div ng-model="data.card.cvv" id="sq-cvv"></div>
</div>
<div>
<label>Expiration Date</label>
<div ng-model="data.card.expiration_date" id="sq-expiration-date"></div>
</div>
<div>
<label>Postal Code</label>
<div ng-model="data.card.postal_code" id="sq-postal-code"></div>
</div>
<div>
<input ng-click="submitForm()" ng-disabled="isProcessing" type="submit" id="submit" value="Buy Now" class="btn btn-primary">
</div>
</form>
<button id="sq-apple-pay" class="button-apple-pay-block" ng-show="supportApplePay"></button>
</div>
</div>
</div>
</div>
</div>
</div>
the controller:
'use strict';
/* Controllers */
// signin controller
app.controller('PaymentController', ['$scope', '$http', function($scope, $http) {
//for showing #successNotification div
$scope.isPaymentSuccess = false;
//for disabling payment button
$scope.isProcessing = false;
//for disabling apple pay button
$scope.supportApplePay = false;
$scope.data = {
product_id: "001",
user: {},
card: {},
products: {
"001": {
"name": "Paper Origami 1:10,000 scale model (11 inch)",
"value":"1.0",
},
"002": {
"name": "Plastic 1:5000 scale model (22 inch)",
"value":"49.0",
},
"003": {
"name": "Metal & Concrete 1:1000 scale replica (9 feet)",
"value":"5000.0",
}
}
};
$scope.submitForm = function(){
console.log($scope.data)
$scope.isProcessing = true;
$scope.paymentForm.requestCardNonce();
return false
}
var cardNumber = $scope.data.card.card_number = 5409889944179029;
var cvv = $scope.data.card.cvv = 111;
var expirationDate = $scope.data.card.expirationDate = '02/21';
var postalCode = $scope.data.card.postalCode = 3311;
$scope.paymentForm = new SqPaymentForm({
applicationId: 'sandbox-sq0idp-IsHp4BXhhVus21G5JPyYpw',
locationId: 'CBASECJCvmqtoIL1fn3iReEjQRcgAQ',
inputClass: 'sq-input',
inputStyles: [
{
fontSize: '14px',
padding: '7px 12px',
backgroundColor: "transparent"
}
],
cardNumber: {
elementId: 'sq-card-number',
placeholder: '5409889944179029',
value: '5409889944179029'
},
cvv: {
elementId: 'sq-cvv',
placeholder: '111',
value: '111'
},
expirationDate: {
elementId: 'sq-expiration-date',
placeholder: '04/21',
value: '04/21'
},
postalCode: {
elementId: 'sq-postal-code',
placeholder: '33114',
value: '33114'
},
applePay: {
elementId: 'sq-apple-pay'
},
// cardNumber:''+cardNumber,
// cvv:''+cvv,
// expirationDate:''+expirationDate,
// postalCode:''+postalCode,
callbacks: {
cardNonceResponseReceived: function(errors, nonce, cardData) {
if (errors){
$scope.card_errors = errors
$scope.isProcessing = false;
$scope.$apply(); // required since this is not an angular function
}else{
$scope.card_errors = []
$scope.chargeCardWithNonce(nonce);
}
},
unsupportedBrowserDetected: function() {
// Alert the buyer
},
methodsSupported: function (methods) {
console.log(methods);
$scope.supportApplePay = true
$scope.$apply(); // required since this is not an angular function
},
createPaymentRequest: function () {
var product = $scope.data.products[$scope.data.product_id];
return {
requestShippingAddress: true,
currencyCode: "USD",
countryCode: "US",
total: {
label: product["name"],
amount: product["value"],
pending: false,
}
};
},
// Fill in these cases to respond to various events that can occur while a
// buyer is using the payment form.
inputEventReceived: function(inputEvent) {
switch (inputEvent.eventType) {
case 'focusClassAdded':
// Handle as desired
break;
case 'focusClassRemoved':
// Handle as desired
break;
case 'errorClassAdded':
// Handle as desired
break;
case 'errorClassRemoved':
// Handle as desired
break;
case 'cardBrandChanged':
// Handle as desired
break;
case 'postalCodeChanged':
// Handle as desired
break;
}
}
}
});
$scope.chargeCardWithNonce = function(nonce) {
alert("no");
var url = "libs/php_payment/process-card.php";
var data = {
nonce: nonce,
product_id: $scope.data.product_id,
name: $scope.data.user.name,
email: $scope.data.user.email,
street_address_1: $scope.data.user.street_address_1,
street_address_2: $scope.data.user.street_address_2,
city: $scope.data.user.city,
state: $scope.data.user.state,
zip: $scope.data.user.zip
};
$http.post(url, data).success(function(data, status) {
if (data.status == 400){
// display server side card processing errors
$scope.isPaymentSuccess = false;
$scope.card_errors = []
for (var i =0; i < data.errors.length; i++){
$scope.card_errors.push({message: data.errors[i].detail})
}
}else if (data.status == 200) {
$scope.isPaymentSuccess = true;
}
$scope.isProcessing = false;
}).error(function(){
$scope.isPaymentSuccess = false;
$scope.isProcessing = false;
$scope.card_errors = [{message: "Processing error, please try again!"}];
})
}
//build payment form after controller loads
var init = function () {
$scope.paymentForm.build()
};
init();
}]);
error: "Error: [$rootScope:inprog] $digest already in progress
I haven't done angular in a while, but I'm betting that your issue is in:
methodsSupported: function (methods) {
console.log(methods);
$scope.supportApplePay = true
$scope.$apply(); // required since this is not an angular function
},
You are calling $apply() after a non-asyc call, generally you apply new data that you got asynchronously. See Angular Docs

VueJs2:remove item from parent array in component

I have a component with prop List. List is list of input files. At once input changed I add another one input.
Weird behavior if I try to delete .
https://jsfiddle.net/apokjqxx/115/
removeAnother: function(item) {
var vm = this;
var num = vm.$parent.cornerList.indexOf(item);
vm.$parent.cornerList.splice(num, 1);
},
How to reproduce:
choose file in first input
choose file in second input (will added after step 1)
choose file in third input (will added after step 2)
then click to remove on first item in list
Expected: removed first item but has removed last added
Use a key on your list.
<div v-for="(item, index) in list" :key="item.id">
I modified your fiddle to generate an id for each object added to the cornerList array.
var formuploadimage = Vue.extend({
template: '#template-form-upload-image',
props: {
list: {
type: Array
}
},
data: function() {
return {
isFileChanged: false
}
},
watch: {
validCnt: function() {
},
},
methods: {
onFileChange: function(item) {
var vm = this;
let id = Math.max.apply(Math, vm.$parent.cornerList.map(c => c.id)) + 1
var newItem = {id};
vm.$parent.cornerList.push(newItem);
},
removeAnother: function(item) {
var vm = this;
var num = vm.$parent.cornerList.indexOf(item);
vm.$parent.cornerList.splice(num, 1);
},
},
});
var app = new Vue({
el: ".lists-wrappers",
data: {
cornerList: [{id: 1}],
},
components: {
formuploadimage: formuploadimage
},
methods: {
},
});
.select-file{
width:250px;
border:1px solid red;
}
<script src="https://unpkg.com/vue#2.4.4/dist/vue.js"></script>
<div class="lists-wrappers">
<formuploadimage :list="cornerList"></formuploadimage>
</div>
<script type="text/x-template" id="template-form-upload-image">
<div>
<div v-for="(item, index) in list" :key="item.id">
<div class="select-file">
REMOVE<br/>
<label for="file-input">
+Add photo
</label>
<input type="file" #change="onFileChange(item)" />
</div>
</div>
</div>
</script>

How to Add a product to the cart and then update the quantity from both the product page and from the cart itself.

I am completely stumped on how to achieve something specific that the below website has achieved. Does anyone know how to update the quantity of a product from the product details page to the shopping cart, and have that quantity shared/bound between the cart and and the product details page for each an every product repeated from a collection. (I am not talking about simply having a global cart quantity total via a simple custom directive). Please see the link below. Add a product to the cart and then update the quantity from both the product page and from the cart itself. This is what I am trying to achieve. Thank you all in advance!
http://demo.shopnx.in/
Typically you'll get better responses if you post some code that you have tried and then ask to be guided on where you are going wrong. I've created a simple JSFiddle to demonstrate one method of doing this. It is extremely simple, contrived, not production worthy by any stretch of the imagination and doesn't really do much, but it should show you one construct that will allow you to accomplish the functionality you're after.
The key is to use some type of shared storage so that the same array of items is available to both your product listing and the cart. In the sample I have done this using a Value:
.value('cartStorage', {
items: []
})
This value is then injected in the main controller:
.controller('mainController', function(cartStorage) {
var _this = this;
_this.cartStorage = cartStorage;
_this.items = [{
name: 'Apple',
price: .5,
quantity: 0,
showAddToCart: false,
addedToCart: false
}, {
name: 'Orange',
price: .5,
quantity: 0,
showAddToCart: false,
addedToCart: false
}, {
name: 'Grapes',
price: 1,
quantity: 0,
showAddToCart: false,
addedToCart: false
}];
_this.addToCart = function(item) {
_this.cartStorage.items.push(item);
item.addedToCart = true;
}
_this.increaseItemAmount = function(item) {
item.quantity++;
item.showAddToCart = true;
}
_this.decreaseItemAmount = function(item) {
item.quantity--;
if (item.quantity <= 0) {
item.quantity = 0;
item.addedToCart = false;
item.showAddToCart = false;
var itemIndex = _this.cartStorage.items.indexOf(item);
if (itemIndex > -1) {
_this.cartStorage.items.splice(itemIndex, 1);
}
} else {
item.showAddToCart = true;
}
}
})
As well as the cart controller:
.controller('cartController', function(cartStorage) {
var _this = this;
_this.cartStorage = cartStorage;
_this.increaseItemAmount = function(item) {
item.quantity++;
}
_this.decreaseItemAmount = function(item) {
item.quantity--;
if (item.quantity <= 0) {
item.quantity = 0;
item.addedToCart = false;
item.showAddToCart = false;
var itemIndex = _this.cartStorage.items.indexOf(item);
if (itemIndex > -1) {
_this.cartStorage.items.splice(itemIndex, 1);
}
}
}
_this.removeFromCart = function(item) {
item.quantity = 0;
item.addedToCart = false;
item.showAddToCart = false;
var itemIndex = _this.cartStorage.items.indexOf(item);
if (itemIndex > -1) {
_this.cartStorage.items.splice(itemIndex, 1);
}
}
})
Now the cartStorage object is shared so any update made in one controller will automagically be reflected in the other controller. All that's left is the markup:
<div ng-app="app">
<div ng-controller="mainController as main">
<h2>Main Controller</h2>
<div>
<table>
<tr>
<td>Item</td>
<td>Price</td>
<td>Quantity</td>
<td></td>
</tr>
<tr ng-repeat="item in main.items">
<td>{{item.name}}</td>
<td>{{item.price | currency}}</td>
<td>{{item.quantity}}</td>
<td>
<button ng-click="main.increaseItemAmount(item)">+</button>
<button ng-click="main.decreaseItemAmount(item)">-</button>
<button ng-click="main.addToCart(item)" ng-show="item.showAddToCart && !item.addedToCart">Add to Cart</button>
</td>
</tr>
</table>
</div>
</div>
<div ng-controller="cartController as cart">
<h2>Cart Controller</h2>
<div>
<table>
<tr>
<td>Item</td>
<td>Price</td>
<td>Quantity</td>
<td></td>
</tr>
<tr ng-repeat="item in cart.cartStorage.items">
<td>{{item.name}}</td>
<td>{{item.price | currency}}</td>
<td>{{item.quantity}}</td>
<td>
<button ng-click="cart.increaseItemAmount(item)">+</button>
<button ng-click="cart.decreaseItemAmount(item)">-</button>
<button ng-click="cart.removeFromCart(item)">Remove from Cart</button>
</td>
</tr>
</table>
</div>
</div>
</div>
Update showing the usage of a Factory instead of Value
Instead of using a Value use this service:
.factory('cartStorage', function() {
var _cart = {
items: []
};
var service = {
get cart() {
return _cart;
}
}
return service;
})
Then modify the code in the controllers to use the .cart property of the service instead of the value. You only need to change one line of code in both controllers. Change:
_this.cartStorage = cartStorage;
to:
_this.cartStorage = cartStorage.cart;
Here is an updated JSFiddle.
I made this plunker as an example.
I've used events to achieve the desired behavior. (
This is just one way of doing this, should have a lot of possibilities)
ProductsController:
app.controller('ProductsCtrl', function($scope, $rootScope) {
$scope.products = [
{
'name': 'Product One',
'price': 10,
'qty': 0
},
{
'name': 'Product two',
'price': 20,
'qty': 0
}
];
// Fire event to add
$scope.add = function(product) {
product.qty++;
$rootScope.$broadcast('addProduct', product.price);
}
// Fire event to remove
$scope.remove = function(product) {
if(product.qty > 0) {
product.qty--;
$rootScope.$broadcast('removeProduct', product.price);
}
}
});
CartController:
app.controller('CartCtrl', function($scope) {
$scope.total = 0;
// Catch the event to add
$scope.$on('addProduct', function(event, data) {
$scope.total += data;
});
// Catch the event to remove
$scope.$on('removeProduct', function(event, data) {
$scope.total -= data;
});
});
View:
<div ng-controller="CartCtrl">Total: {{total}}</div>
<br>
<div ng-controller="ProductsCtrl">
<div ng-repeat="product in products">
<span>Name: {{product.name}}</span>
<br>
<span>Price:{{product.price}}</span>
<span>Quantity:{{product.qty}}</span>
<br>
<button type="button" ng-click="add(product);">Add</button>
<button type="button" ng-click="remove(product);">Remove</button>
<br><br><br>
</div>
</div>
You can have a shared service between your Product details and Cart detail controller which can have an array where you can push the the Product selected with its quantity and other details.

How to Keep track of all clicks on page in ionic application?

I have created simple page which contains check boxes. On this page user can check and uncheck boxes multiple times. I want to keep track of all these events? How Can I do that?
here is my code.
app.js
var pmApp = angular.module('pmApp', ['ionic']);
pmApp.controller('CheckboxController', function($scope) {
$scope.devList = [
{ text: "Device & app history", details : "Allows the app to view one or more of: information about activity on the device, which apps are running, browsing history and bookmarks" ,checked: true },
{ text: "Identity", details: "Uses one or more of: accounts on the device, profile data", checked: false },
{ text: "Calendar", details: "Uses calendar information", checked: false },
{ text: "Contact", details: "Uses contact information", checked: false },
{ text: "Location", details: "Uses the device's location", checked: false },
{ text: "SMS", details: "Uses one or more of: SMS, MMS. Charges may apply.", checked: false }
];
$scope.selection=[];
// toggle selection for a given employee by name
$scope.toggleSelection = function toggleSelection(item) {
var idx = $scope.selection.indexOf(item);
// is currently selected
if (idx > -1) {
$scope.selection.splice(idx, 1);
}
// is newly selected
else {
$scope.selection.push(item);
}
};
});
index.html
<div class="list" ng-controller="CheckboxController">
<ion-checkbox ng-repeat="item in devList"
ng-model="item.checked"
ng-checked="selection.indexOf(item) > -1"
ng-click="toggleSelection(item)"
>
{{ item.text }}
<h3 class="item-text-wrap"> {{ item.details }}</h3>
</ion-checkbox>
<div class="item">
<pre ng-bind="selection | json"></pre>
</div>
</div>
Thanks in advance, any help would be appreciated.
Regards
You can use https://docs.angularjs.org/api/ng/directive/ngMouseover to make a counter for mouse hovers on all your elements: and then use
https://docs.angularjs.org/api/ng/directive/ngClick to record clicks and https://docs.angularjs.org/api/ng/directive/ngMousemove to record the mouse being moved and get the position:
Everything Used:
ng-click
ng-dblclick
ng-mousedown
ng-mouseup
ng-mouseenter
ng-mouseleave
ng-mousemove
ng-mouseover
Here is some example code:
HTML:
<body ng-app="mainModule">
<div ng-controller="mainController">
<h3>1. Click</h3>
<button id="firstBtn" ng-click="onFirstBtnClick()">Click me</button>
<strong>RESULT:</strong> {{onFirstBtnClickResult}}<br />
<br />
<h3>2. Click with Dependency Injection</h3>
<label>Type something: <input type="text" ng-model="secondBtnInput"></label>
<button id="secondBtn" ng-click="onSecondBtnClick(secondBtnInput)">Click me</button><br />
<strong>RESULT:</strong> {{onSecondBtnClickResult}}<br />
<br />
<h3>3. Double click</h3>
Double-click the square<br />
<img src="images/square.png" ng-dblclick="onDblClick()" /><br />
<strong>RESULT:</strong> {{onDblClickResult}}<br />
<h3>4. Mouse down, up, enter, leave, move, over</h3>
Move the mouse on the square<br />
<img src="images/square.png"
ng-mousedown="onMouseDown($event)"
ng-mouseup="onMouseUp($event)"
ng-mouseenter="onMouseEnter($event)"
ng-mouseleave="onMouseLeave($event)"
ng-mousemove="onMouseMove($event)"
ng-mouseover="onMouseOver($event)" /><br />
<strong>MOUSE DOWN RESULT:</strong> {{onMouseDownResult}}<br />
<strong>MOUSE UP RESULT:</strong> {{onMouseUpResult}}<br />
<strong>MOUSE ENTER RESULT:</strong> {{onMouseEnterResult}}<br />
<strong>MOUSE LEAVE RESULT:</strong> {{onMouseLeaveResult}}<br />
<strong>MOUSE MOVE RESULT:</strong> {{onMouseMoveResult}}<br />
<strong>MOUSE OVER RESULT:</strong> {{onMouseOverResult}}
</div>
</body>
</html>
JS
angular.module("mainModule", [])
.controller("mainController", function ($scope)
{
// Initialization
$scope.onFirstBtnClickResult = "";
$scope.secondBtnInput = "";
$scope.onDblClickResult = "";
$scope.onMouseDownResult = "";
$scope.onMouseUpResult = "";
$scope.onMouseEnterResult = "";
$scope.onMouseLeaveResult = "";
$scope.onMouseMoveResult = "";
$scope.onMouseOverResult = "";
// Utility functions
// Accepts a MouseEvent as input and returns the x and y
// coordinates relative to the target element.
var getCrossBrowserElementCoords = function (mouseEvent)
{
var result = {
x: 0,
y: 0
};
if (!mouseEvent)
{
mouseEvent = window.event;
}
if (mouseEvent.pageX || mouseEvent.pageY)
{
result.x = mouseEvent.pageX;
result.y = mouseEvent.pageY;
}
else if (mouseEvent.clientX || mouseEvent.clientY)
{
result.x = mouseEvent.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
result.y = mouseEvent.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
if (mouseEvent.target)
{
var offEl = mouseEvent.target;
var offX = 0;
var offY = 0;
if (typeof(offEl.offsetParent) != "undefined")
{
while (offEl)
{
offX += offEl.offsetLeft;
offY += offEl.offsetTop;
offEl = offEl.offsetParent;
}
}
else
{
offX = offEl.x;
offY = offEl.y;
}
result.x -= offX;
result.y -= offY;
}
return result;
};
var getMouseEventResult = function (mouseEvent, mouseEventDesc)
{
var coords = getCrossBrowserElementCoords(mouseEvent);
return mouseEventDesc + " at (" + coords.x + ", " + coords.y + ")";
};
// Event handlers
$scope.onFirstBtnClick = function () {
$scope.onFirstBtnClickResult = "CLICKED";
};
$scope.onSecondBtnClick = function (value) {
$scope.onSecondBtnClickResult = "you typed '" + value + "'";
};
$scope.onDblClick = function () {
$scope.onDblClickResult = "DOUBLE-CLICKED";
};
$scope.onMouseDown = function ($event) {
$scope.onMouseDownResult = getMouseEventResult($event, "Mouse down");
};
$scope.onMouseUp = function ($event) {
$scope.onMouseUpResult = getMouseEventResult($event, "Mouse up");
};
$scope.onMouseEnter = function ($event) {
$scope.onMouseEnterResult = getMouseEventResult($event, "Mouse enter");
};
$scope.onMouseLeave = function ($event) {
$scope.onMouseLeaveResult = getMouseEventResult($event, "Mouse leave");
};
$scope.onMouseMove = function ($event) {
$scope.onMouseMoveResult = getMouseEventResult($event, "Mouse move");
};
$scope.onMouseOver = function ($event) {
$scope.onMouseOverResult = getMouseEventResult($event, "Mouse over");
};
});
You could try with the newest Ionic Analytics, if that will suit your needs. More info on their official blog post: http://docs.ionic.io/v1.0/docs/analytics-from-scratch.
Usage is pretty straight forward (from the additional docs):
.controller('MyCtrl', function($ionicAnalytics) {
$ionicAnalytics.track('Purchase Item', {
item_id: 'lpdsx,
item_name: 'Leopard Socks'
});
});

AngularJS checkbox filter directive

I have a AngularJS directive that allows users to select a values from a list to filter on. Pretty simple concept which is represented here:
Problem is when I click one of the checkboxes they all select unintended. My directive is pretty simple so I'm not sure why this is happening. The code around the selection and checkboxes is as follows:
$scope.tempFilter = {
id: ObjectId(),
fieldId: $scope.available[0].id,
filterType: 'contains'
};
$scope.toggleCheck = function (id) {
var values = $scope.tempFilter.value;
if (!values || !values.length) {
values = $scope.tempFilter.value = [];
}
var idx = values.indexOf(id);
if (idx === -1) {
values.push(id);
} else {
values.splice(idx, 1);
}
};
$scope.valuesListValues = function (id) {
return $scope.available.find(function (f) {
return f.id === id;
}).values;
};
and the data resembles:
$scope.available = [{
id: 23,
name: 'Store'
values: [
{ id: 124, name: "Kansas" },
{ id: 122, name: "Florida" }, ... ]
}, ... ]
the view logic is as follows:
<ul class="list-box">
<li ng-repeat="val in valuesListValues(tempFilter.fieldId)">
<div class="checkbox">
<label ng-click="toggleCheck(val.id)">
<input ng-checked="tempFilter.value.indexOf(val.id) === -1"
type="checkbox"> {{val.name}}
</label>
</div>
</li>
</ul>
First off, it toggleCheck fires twice but populates the correct data ( second time given my code it removes it though ).
After the second fire, it checks all boxes... Any ideas?
Perhaps its that the local variable doesn't get reassigned to the property of the scope property used in the view. Since your values are then non-existent and not found, the box is checked.
$scope.tempFilter.value = values
I took the interface concept you were after and created a simpler solution. It uses a checked property, found in each item of available[0].values, as the checkbox model. At the top of the list is a button that clears the selected items.
JavaScript:
function DataMock($scope) {
$scope.available = [{
id: 23,
name: 'Store',
values: [{
id: 124,
name: "Kansas"
}, {
id: 122,
name: "Florida"
}]
}];
$scope.clearSelection = function() {
var values = $scope.available[0].values;
for (var i = 0; i < values.length; i++) {
values[i].checked = false;
}
};
}
HTML:
<body ng-controller="DataMock">
<ul class="list-box">
<li>
<button ng-click="clearSelection()">Clear Selection</button>
</li>
<li ng-repeat="val in available[0].values">
<div class="checkbox">
<label>
<input ng-model="val.checked"
type="checkbox" /> {{val.name}}
</label>
</div>
</li>
</ul>
</body>
Demo on Plunker
The repeat that I used to grab the values based on the id, was the problem area.
<li ng-repeat="val in valuesListValues(tempFilter.fieldId)">
removing that and simple listening and setting a static variable resolved the problem.
$scope.$watch('tempFilter.fieldId', function () {
var fId = $scope.tempFilter.fieldId;
if ($scope.isFieldType(fId, 'valuesList')) {
$scope.valuesListValues = $scope.valuesListValues(fId);
}
}, true);
});
and then in the view:
ng-repeat="value in valuesListValues"

Resources