Select checkbox on load - javascript

After I load all topics from the database I need to select the ones for specific user. How can I do that?
<div ng-repeat="item in topicEditItems">
<md-checkbox ng-checked="existsEditTopic(item, topicEditSelected);" ng-click="toggleEditTopic(item, topicEditSelected);" value="{{item.TopicID}}">
{{item.TopicName}}
</md-checkbox>
</div>
$scope.topicEditSelected = [];
adminService.getTopics().then(function (response) {
$scope.topicEditItems = $.parseJSON(response.data);
//Select topics
})
$scope.toggleEditTopic = function (item, list) {
var idx = list.indexOf(item);
if (idx > -1) {
list.splice(idx, 1);
}
else {
list.push(item);
}
};
$scope.existsEditTopic = function (item, list) {
return list.indexOf(item) > -1;
};

The easiest way is having 2 checkbox mimic to the original 1 then show and hide based on your filter. You may need to apply md-checkbox styling into the fake one
<input type="checkbox" class="check" aria-label="Cb user"
ng-model="cbFake" ng-if="isTopicExist(item.id)" ng-checked="isTopicExist(item.id)"/>
<md-checkbox ng-checked="exists(item, selected)" ng-click="toggle(item, selected)" aria-label="Cb user"
ng-model="cbOri" ng-if="!isTopicExist(item.id)"> </md-checkbox>

update $scope.existsEditTopic to
$scope.existsEditTopic = function (item, list) {
var index = list.indexOf(item);
if(index > -1){
return true;
}else{
return false;
}
};

Related

Angular List color change based ng-click

I am using angularjs I have two list when I click first one I will push the value into another scope and bind the value to second list. Now my requirement is when first list values which are moved to second list, I need to change the color of moved values in list1
Here I attached my fiddle
Fiddle
You can use findIndex and ng-class together to check if the second list contains the same item as first. If present apply css class to the first list item.
JS:
$scope.checkColor = function(text) {
var index = $scope.linesTwos.findIndex(x => x.text === text);
if (index > -1) return true;
else return false;
}
HTML:
<li ng-click="Team($index,line.text)" ng-class="{'change-color':checkColor(line.text)}">{{line.text}}</li>
Working Demo: https://jsfiddle.net/7MhLd/2659/
You can do something like this:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.lines = [{
text: 'res1'
},
{
text: 'res2'
},
{
text: 'res3'
}
];
$scope.linesTwos = [];
$scope.Team = function(index, text) {
var obj = {};
obj.text = text;
$scope.linesTwos.push(obj)
}
$scope.Team2 = function(index, text2) {
$scope.linesTwos.splice(index, 1)
}
$scope.containsObj = function(obj, list) {
var i;
for (i = 0; i < list.length; i++) {
if (angular.equals(list[i], obj)) {
return true;
}
}
return false;
};
}
.clicked {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<ul ng-repeat="line in lines">
<li ng-class="{'clicked': containsObj(line,linesTwos)}" ng-click="Team($index,line.text)">{{line.text}}</li>
</ul>
<ul>
<li>__________</li>
</ul>
<ul ng-repeat="line in linesTwos">
<li ng-click="Team2($index,line.text)">{{line.text}}</li>
</ul>
</div>
you have to achieve it using ng-class and create a dynamic class style for pushed data please check my working example fiddle
JS fiddle sample
in HTML nedd to do these changes
<li ng-click="Team($index,line.text,line)" ng-class="{'pushed':line.pushed}">
<li ng-click="Team2($index,line.text,line)">
In css
.pushed{color:red;}
In Controller
`$scope.Team=function(index,text,line){
var obj={};
obj = line;
$scope.linesTwos.push(obj)
line.pushed = true;
}`
`scope.Team2 = function(index,text2,line){
$scope.linesTwos.splice(index,1)
line.pushed = false;
}
`
its because angular two way binding

Strange behavior when splicing array, javascript

I'm working with list of checkboxes and I have next logic behavior for it:
if all items selected, checkbox "select all" is checked
if one of all selected items has been unchecked, checkbox "select all" is unchecked as well
This logic is clear. Depends of what item is checked I extract its id to an additional array and then using this array for request that to get data.
For pushing everything works fine, but for slicing the logic is strange. So I can slice the array until first item is checked, however I unchecked the first item, pushed and sliced items no more related with checkboxes.
I have reproduced plunker with it, so I appreciate if anybody could help me to find what I'm missing.
$scope.modelClass = {
selectedAll: false
};
$scope.selectAllClass = function (array) {
angular.forEach(array, function (item) {
item.selected = $scope.modelClass.selectedAll;
$scope.param =''
});
};
$scope.checkIfAllClassSelected = function (array) {
$scope.modelClass.selectedAll = array.every(function (item) {
return item.selected == true
});
$scope.checked = array.filter(function (item) {
return item.selected == true
}).length;
angular.forEach(array, function (obj) {
if(obj.selected == true){
requestClass(obj)
}
});
};
var selectedClass = [];
var requestClass = function (obj) {
selectedClass.push(obj);
angular.forEach(selectedClass, function (val) {
if (val.selected != true) {
selectedClass.splice(selectedClass.indexOf(val.id), 1);
}
else {
selectedClass = selectedClass.filter(function (elem, index, self) {
return index == self.indexOf(elem);
})
}
});
$scope.param = _.map(selectedClass, 'id')
};
$scope.classes = [
{"id":4,"name":"Achievement","selected":false},
{"id":13,"name":"Information","selected":false},
{"id":6,"name":"Issue","selected":false},
{"id":5,"name":"Message","selected":false},
{"id":9,"name":"Request","selected":false}
]
The logic looks good for me, not sure what's wrong here. I've took the first solution from this post (it looks like you are using the second one) and slightly modified it for your needs.
$scope.model = {
selectedClass : []
}
$scope.isSelectAll = function(){
$scope.model.selectedClass = [];
if($scope.master){
$scope.master = true;
for(var i=0;i<$scope.classes.length;i++){
$scope.model.selectedClass.push($scope.classes[i].id);
}
}
else{
$scope.master = false;
}
angular.forEach($scope.classes, function (item) {
item.selected = $scope.master;
});
$scope.param = $scope.model.selectedClass
}
$scope.isChecked = function() {
var id = this.item.id;
if(this.item.selected){
$scope.model.selectedClass.push(id);
if($scope.model.selectedClass.length == $scope.classes.length ){$scope.master = true;
}
} else {
$scope.master = false;
var index = $scope.model.selectedClass.indexOf(id);
$scope.model.selectedClass.splice(index, 1);
}
$scope.param = $scope.model.selectedClass
}
$scope.classes = [
{"id":4,"name":"Achievement","selected":false},
{"id":13,"name":"Information","selected":false},
{"id":6,"name":"Issue","selected":false},
{"id":5,"name":"Message","selected":false},
{"id":9,"name":"Request","selected":false}
]
html
<div ng-class="{'selected': master, 'default': !master}">
<div>
<input type="checkbox" ng-model="master" ng-change="isSelectAll()" > Select all
</div>
</div>
<div ng-repeat="item in classes | orderBy : 'id'" ng-class="{'selected': item.selected, 'default': !item.selected}">
<div >
<input type="checkbox" ng-model="item.selected" ng-change="isChecked()">
{{ item.name }}
</div>
</div>
this is fixed plunker

Couldn't append span element to array object in Angularjs/Jquery

Am struggling hard to bind an array object with list of span values using watcher in Angularjs.
It is partially working, when i input span elements, an array automatically gets created for each span and when I remove any span element -> respective row from the existing array gets deleted and all the other rows gets realigned correctly(without disturbing the value and name).
The problem is when I remove a span element and reenter it using my input text, it is not getting added to my array. So, after removing one span element, and enter any new element - these new values are not getting appended to my array.
DemoCode fiddle link
What am I missing in my code?
How can I get reinserted spans to be appended to the existing array object without disturbing the values of leftover rows (name and values of array)?
Please note that values will get changed any time as per a chart.
This is the code am using:
<script>
function rdCtrl($scope) {
$scope.dataset_v1 = {};
$scope.dataset_wc = {};
$scope.$watch('dataset_wc', function (newVal) {
//alert('columns changed :: ' + JSON.stringify($scope.dataset_wc, null, 2));
$('#status').html(JSON.stringify($scope.dataset_wc));
}, true);
$(function () {
$('#tags input').on('focusout', function () {
var txt = this.value.replace(/[^a-zA-Z0-9\+\-\.\#]/g, ''); // allowed characters
if (txt) {
//alert(txt);
$(this).before('<span class="tag">' + txt.toLowerCase() + '</span>');
var div = $("#tags");
var spans = div.find("span");
spans.each(function (i, elem) { // loop over each spans
$scope.dataset_v1["d" + i] = { // add the key for each object results in "d0, d1..n"
id: i, // gives the id as "0,1,2.....n"
name: $(elem).text(), // push the text of the span in the loop
value: 3
}
});
$("#assign").click();
}
this.value = "";
}).on('keyup', function (e) {
// if: comma,enter (delimit more keyCodes with | pipe)
if (/(188|13)/.test(e.which)) $(this).focusout();
if ($('#tags span').length == 7) {
document.getElementById('inptags').style.display = 'none';
}
});
$('#tags').on('click', '.tag', function () {
var tagrm = this.innerHTML;
sk1 = $scope.dataset_wc;
removeparent(sk1);
filter($scope.dataset_v1, tagrm, 0);
$(this).remove();
document.getElementById('inptags').style.display = 'block';
$("#assign").click();
});
});
$scope.assign = function () {
$scope.dataset_wc = $scope.dataset_v1;
};
function filter(arr, m, i) {
if (i < arr.length) {
if (arr[i].name === m) {
arr.splice(i, 1);
arr.forEach(function (val, index) {
val.id = index
});
return arr
} else {
return filter(arr, m, i + 1)
}
} else {
return m + " not found in array"
}
}
function removeparent(d1)
{
dataset = d1;
d_sk = [];
Object.keys(dataset).forEach(function (key) {
// Get the value from the object
var value = dataset[key].value;
d_sk.push(dataset[key]);
});
$scope.dataset_v1 = d_sk;
}
}
</script>
Am giving another try, checking my luck on SO... I tried using another object to track the data while appending, but found difficult.
You should be using the scope as a way to bridge the full array and the tags. use ng-repeat to show the tags, and use the input model to push it into the main array that's showing the tags. I got it started for you here: http://jsfiddle.net/d5ah88mh/9/
function rdCtrl($scope){
$scope.dataset = [];
$scope.inputVal = "";
$scope.removeData = function(index){
$scope.dataset.splice(index, 1);
redoIndexes($scope.dataset);
}
$scope.addToData = function(){
$scope.dataset.push(
{"id": $scope.dataset.length+1,
"name": $scope.inputVal,
"value": 3}
);
$scope.inputVal = "";
redoIndexes($scope.dataset);
}
function redoIndexes(dataset){
for(i=0; i<dataset.length; i++){
$scope.dataset[i].id = i;
}
}
}
<div ng-app>
<div ng-controller="rdCtrl">
<div id="tags" style="border:none;width:370px;margin-left:300px;">
<span class="tag" style="padding:10px;background-color:#808080;margin-left:10px;margin-right:10px;" ng-repeat="data in dataset" id="4" ng-click="removeData($index)">{{data.name}}</span>
<div>
<input type="text" style="margin-left:-5px;" id="inptags" value="" placeholder="Add ur 5 main categories (enter ,)" ng-model="inputVal" />
<button type="submit" ng-click="addToData()">Submit</button>
<img src="../../../static/app/img/accept.png" ng-click="assign()" id="assign" style="cursor:pointer;display:none" />
</div>
</div>
<div id="status" style="margin-top:100px;"></div>
</div>
</div>

Issue with <select ng-options="..." />

I tried to achieve a simple feature with AngularJS as below. In item list, when user clicks an item and click the Remove button then the item will be removed.
html:
<div ng-app="app" ng-controller="MainController">
<div>
<select ng-options="item.name for item in items" ng-model="currentItem" size="5" style="width: 200px"></select>
</div>
<button ng-click="removeItem()">Remove</button>
</div>
and script is like below:
angular.module('app', [])
.controller('MainController', function($scope) {
$scope.items = [{
name: 'item1'
}, {
name: 'item2'
}, {
name: 'item3'
}];
$scope.currentItem = $scope.items[0];
$scope.removeItem = function() {
var index = $scope.items.indexOf($scope.currentItem);
$scope.items.splice(index, 1);
};
});
The problem is when I tried to remove an item (i.e. item2), the list always shows an empty item in the first position. When I click 'item1' or 'item3', the empty item disappears.
I know that this is caused by ng-model="currentItem" in html. The item that currentItem points to get removed, currentItem points to null. So I changed the function removeItem as below to solve this issue.
$scope.removeItem = function() {
var index = $scope.items.indexOf($scope.currentItem);
$scope.items.splice(index, 1);
/* PART 1 begin */
if ($scope.items.length === 0) {
$scope.currentItem = null;
} else {
if (index >= 0 && index <= $scope.items.length - 1) {
$scope.currentItem = $scope.items[index];
} else {
$scope.currentItem = $scope.items[$scope.items.length - 1];
}
}
/* PART 1 end */
};
I would like to know whether there is any simple way (like a directive) in AngularJS to do the action in PART 1 automatically.
There is simple way in which you can prevent that is just include
<option value="" ng-show="false"></option>
in select like as shown below
<select ng-options="item as item.name for item in items" ng-model="currentItem" size="5" style="width: 200px">
<option value="" ng-show="false"></option>
</select>
Working Demo
UPDATE 1
I have resolved the issue of not highlighting the last item, Take a look the working demo
$scope.removeItem = function () {
var index = $scope.items.indexOf($scope.currentItem);
$scope.items.splice(index, 1);
index === $scope.items.length ? $scope.currentItem = $scope.items[index - 1] : $scope.currentItem = $scope.items[index];
};
Working Demo

Calculate summary with AngularJs on selected checkboxes

I'm learning the AngularJs and I've created a dynamic list with ng-repeat, but now I cannot find the solution for the next step...
I have the following code:
HTML:
<div ng-app="app">
<div class="list" ng-controller="ListController">
<div class="row" ng-repeat="prod in prodList">
<div class="prod-name cell">
<input type="checkbox" id="prod-{{ prod.id }}" data-ng-model="orders.prods.prod[prod.id]" value="{{ prod.id }}" data-cb="" /><label for="prod-{{ prod.id }}">{{ prod.name }}</label>
</div>
<div class="prod-size cell">
<label for="prodColor-#{{ prod.id }}">
<select id="prodColor-{{ prod.id }}" data-ng-model="orders.prods.color[prod.id]" data-ng-options="color.id as color.name for color in prod.colors">
<option value="">Select one</option>
</select>
</label>
</div>
<div class="prod-price cell">
{{ prod.price }}
</div>
</div>
<div class="sum">
{{ sum }}
</div>
</div>
</div>
JS:
var app = angular.module("app", [], function () {
});
app.controller('ListController', function ($scope) {
init();
function init () {
$scope.prodList = [{"id":"1","name":"window","colors":[{"id":"9","name":"white"},{"id":"11","name":"black"}],"price":"100"},{"id":"2","name":"door","colors":[{"id":"22","name":"blue"},{"id":"23","name":"red"}],"price":"356"},{"id":"3","name":"table","colors":[{"id":"37","name":"white"},{"id":"51","name":"black"}],"price":"505"}];
$scope.orders = {};
$scope.orders.prods = {};
$scope.orders.prods.prod = {};
$scope.orders.prods.color = {};
$scope.sum = 0;
}
});
Working demo:
http://jsfiddle.net/HDrzR/
Question
How can I calculate the summary of selected product's price into the $scope.sum?
Edited:
So if you select the "window" and the "table" from the list, the sum should contains 606. But if you unselect the "table" then the sum should be 100.
Thank you in advance!
You could either $watch over $scope.orders.prod and re-calculate the sum or (if performance is not a major concern and the list of objects is not huge) you could use a sum() function and reference it in the view:
Total: {{sum()}}
$scope.sum = function () {
return $scope.prodList.filter(function (prod) {
return $scope.orders.prods.prod[prod.id];
}).reduce(function (subtotal, selectedProd) {
return subtotal + parseInt(selectedProd.price);
}, 0);
};
/* If the above looks complicated, it is the equivalent of: */
$scope.sum = function () {
var sum = 0;
for (var i = 0; i < $scope.prodList.length, i++) {
var prod = $scope.prodList[i];
if ($scope.orders.prods.prod[prod.id]) {
sum += parseInt(prod.price);
}
}
return sum;
}
If you decide to go down the watching path, this is how the code should look like:
Total: {{watchedSum}}
$scope.sum = ...; // same as above
$scope.$watchCollection('orders.prods.prod', function (newValue, oldValue) {
if (newValue !== undefined) {
$scope.watchedSum = $scope.sum();
}
});
UPDATE:
"Stole" Quad's $watchCollection as this is more "cheap" than $watch(..., true).
As long as $scope.order.prods.prod contains only rimitive values (i.e. no objects), $watchCollection is enough to detect the changes.
See, also, this short demo illustrating both approaches.
here is an updated fiddle.
http://jsfiddle.net/HRQ9u/
what I did is add a $scope.$watch on the orders:
$scope.$watch('orders', function (newValue, oldValue) {
var findProdById = function (products, id) {
for (var i = 0; i < products.length; i++) {
if (parseInt(products[i].id, 10) === parseInt(id, 10)) {
return products[i];
}
}
return null;
};
var orders = newValue;
var usedProducts = newValue.prods.prod;
var sum = 0;
for ( var prop in usedProducts ){
var prodList = $scope.prodList;
var id = prop;
if ( usedProducts[id] ){
var product = findProdById(prodList, id);
if ( product !== null ){
sum += parseInt(product.price, 10);
}
}
}
$scope.sum = sum;
}, true);
Edit:
With that said, you can probably simplify your model a lot. And I mean A LOT.
Also, I have used only regular js as opposed to lodash or underscore.
Register an ng-click with checkbox and pass $event & prod.id references to a custom function that will be called on checkbox click event.
<input type="checkbox" id="prod-{{ prod.id }}" data-ng-model="orders.prods.prod[prod.id]" value="{{ prod.price }}" ng-click="calcSum($event, prod.id)" data-cb="" />
Within controller define custom function as:
$scope.calcSum = function($event, id) {
var checkbox = $event.target;
if (checkbox.checked ) {
$scope.sum += parseInt(checkbox.value);
} else {
$scope.sum -= parseInt(checkbox.value);
}
}
Change the Checkbox value attribute to store {{ prod.price }} instead of {{ prod.id }}, it makes more sense.
From my POV it looks more appropriate to use is ngChange from the input[checkbox] itself. Like:
ng-change="addMe(prod.price);"
We need a way to differentiate checked from not checked and in order to change less your app we will use the existence of the object by it doing this way:
ng-change="addMe(orders.prods.prod[prod.id],prod.price);"
ng-true-value="{{ prod.id }}"
ng-false-value=""
The full HTML will look like this:
<input type="checkbox" id="prod-{{ prod.id }}" data-ng-model="orders.prods.prod[prod.id]" ng-change="addMe(orders.prods.prod[prod.id],prod.price);" ng-true-value="{{ prod.id }}" ng-false-value="" />
From your Controller all you need is to add or substract when necessary:
$scope.addMe=function(checked,val){
val = 1*val
if (!checked){ $scope.sum = $scope.sum-val;}
else { $scope.sum = $scope.sum +val; }
}
Here is the Online Demo
Updated your fiddle FIDDLE
You can $scope.$watchCollection your scope to calcuate new sum. I chaged your prodList prices to number instead of string, and used underscore.js for easier looping in your objects/arrays.
$scope.$watchCollection("orders.prods.prod",function(){
var sum = 0;
for(var i = 0;i<$scope.prodList.length;i++){
if($scope.orders.prods.prod[$scope.prodList[i].id]){
sum += $scope.prodList[i].price;
}
}
$scope.sum = sum;
});
watchCollection docs are here
edit: changed with regular js answer

Categories

Resources