Custom Filtering Shared Data in Angular - angularjs

I'm trying to filter data from a factory that can becontrolled by booleans. I can't figure out what I'm doing wrong. It's probally the syntax and myself not understanding angular right. but I've been frozen here fror a while and cannot get past. I'm showing a product list and filter it through ng-repeat directive and custom filter.
.filter('promos'[
'$scope', '$http', 'FilterData', 'ProductData', function(
$scope, $http, FilterData, ProductData){
$scope.filterData = FilterData;
$scope.products = ProductData;
angular.forEach(products, function(product){
var promoProducts = [];
//booleen filters- if all or none selected do nothing - full product list
if ($scope.filterData.topChoices[0].selected && $scope.filterData.topChoices[1].selected && $scope.filterData.topChoices[2].selected || $scope.filterData.topChoices[0].selected === false && $scope.filterData.topChoices[1].selected === false && $scope.filterData.topChoices[2].selected === false ) {}
else {
//if option selects, show corresponding products
if ($scope.filterData.topChoices[0].selected && product.onPromotion) {promoProducts.push}
if ($scope.filterData.topChoices[1].selected && product.hotSeller) {promoProducts.push}
if ($scope.filterData.topChoices[2].selected && product.freeShip) {promoProducts.push}
return promoProducts;
}
});
}])
Controller & Factories can be seen in the plunker [http://plnkr.co/edit/EDZPOPh7iMFSpPjO6AkI?p=preview][1]
Here is the html:
<div ng-controller="prodCtrl">
<md-input-container class="md-icon-float md-icon-right md-block">
<label>Low Price</label>
<md-icon md-font-icon="fa fa-money"></md-icon>
<input ng-model="filterData.price.low" type="number" step="5">
<md-icon md-svg-src="img/icons/ic_euro_24px.svg"></md-icon>
</md-input-container>
<md-input-container class="md-icon-float md-icon-right md-block">
<label>High Price</label>
<md-icon md-font-icon="fa fa-money"></md-icon>
<input ng-model="filterData.price.high" type="number" step="5">
<md-icon md-svg-src="img/icons/ic_euro_24px.svg"></md-icon>
</md-input-container>
<md-checkbox style="margin-left: 15px;" class="md-secondary" ng-model="filterData.topChoices[0].selected"> Show Promotions <br><span style="font-size: 10px; color: blue;" ng-if="filterData.topChoices[0].selected">selected</span> </md-checkbox>
<md-checkbox style="margin-left: 15px;" class="md-secondary" ng-model="filterData.topChoices[1].selected"> Show Hot Sellers<br><span style="font-size: 10px; color: blue;" ng-if="filterData.topChoices[1].selected">selected</span> </md-checkbox>
<md-checkbox style="margin-left: 15px;" class="md-secondary" ng-model="filterData.topChoices[2].selected"> Show Free Shipping<br><span style="font-size: 10px; color: blue;" ng-if="filterData.topChoices[2].selected">selected</span> </md-checkbox>
</div>
<md-subheader class="md-no-sticky">Avatar with Secondary Action Icon</md-subheader>
<md-list ng-Controller="prodCtrl">
<md-list-item ng-repeat="product in products | filter:promos" ng-click class="noright">
<ul>
<h3>{{product.name}} </h3>
<p>{{product.desc}}</p>
</ul>
<ul class="md-secondary">
<li style="list-style: none;" ng-if="product.onPromotion">On Promotion!</li>
<li style="list-style: none;" ng-if="product.hotSeller">Hot-Seller!</li>
<li style="list-style: none;" ng-if="product.freeShip">Free Shipping!</li>
</ul>
<ul class="md-secondary" style="margin-right: 25px;">
<li style="list-style: none;" ng-repeat="item in product.sellers | orderBy: item.price">
{{item.seller}} ${{item.price}}</li>
</ul>
<md-button class="md-raised md-primary md-secondary">Buy</md-button>
</md-list-item>
</md-list>
Please help put me on the right direction. I'm usuing a factory because i also use the product data in a map. So I'm thinking this is the best route.

This will go inside you filter code
remove $http and $scope dependencies from the filter
heres a working fiddle
var pusher = function(main, toPush) {
var alreadyPresent = false;
angular.forEach(main, function(toCheck) {
if (toCheck === toPush) {
alreadyPresent = true;
}
})
if (!alreadyPresent) {
main.push(toPush);
}
}
var p = [];
angular.forEach(products, function(product) {
if (FilterData.topChoices[0].selected &&
FilterData.topChoices[1].selected && FilterData.topChoices[2].selected || FilterData.topChoices[0].selected === false && FilterData.topChoices[1].selected === false && FilterData.topChoices[2].selected === false) {} else {
//if
if (FilterData.topChoices[0].selected && product.onPromotion) {
pusher(p, product);
}
if (FilterData.topChoices[1].selected && product.hotSeller) {
pusher(p, product);
}
if (FilterData.topChoices[2].selected && product.freeShip) {
pusher(p, product);
}
console.log('ppp')
console.log(p);
console.log('--ppp')
}
})
return p;
and to use the filter do
<md-list-item ng-repeat="product in products | promo" ng-click class="noright">

Related

how to toggle a checkbox with no id using protractor

I am new into protractor e2e. I am trying to toggle a checkbox with no id. How do I get the value if the checkbox is checked or not?
<div class="bootstrap-switch bootstrap-switch-wrapper bootstrap-switch-mini bootstrap-switch-on bootstrap-switch-animate" style="width: 62px;">
<div class="bootstrap-switch-container" style="width: 90px; margin-left: 0px;">
<span class="bootstrap-switch-handle-on bootstrap-switch-success" style="width: 30px;">Yes</span>
<span class="bootstrap-switch-label" style="width: 30px;"> </span>
<span class="bootstrap-switch-handle-off bootstrap-switch-danger" style="width: 30px;">No</span>
<input type="checkbox" data-bind="bootstrapSwitchOn: IsActive, v1:$root.isenable" data-on-text="Yes" data-off-text="No" data-size="mini" data-handle-width="20px" data-label-width="20px" data-on-color="success" data-off-color="danger">
</div>
</div>
<label class="checkbox-inline" data-bind="text: window.LabelVM.workflow_details_active,attr: { 'data-title': window.LabelVM.workflow_details_active, 'data-con': window.LabelVM.Active_popover, 'data-popover': 'popover' }" data-tab="3" data-orientation="right" data-title="Is Active" data-con="Activate your workflow for it to appear in Self Service. If a Workflow isn&#39;t active, it cannot be accessed by a staff member" data-popover="popover">Is Active</label>
You should try making your check to be based on the presence of the bootstrap-switch-on class that I assume indicates that the checkbox is set/checked.
Something along these lines:
function checkValue (checkbox) {
checkbox.getAttribute("class").then(function (classes) {
var switchOn = classes.indexOf("bootstrap-switch-on") >= 0;
if (switchOn) {
console.log("Switch is on");
} else {
console.log("Switch is off");
}
});
}
var checkbox = $(".bootstrap-switch");
checkValue(checkbox);
checkbox.click();
checkValue(checkbox);
(not tested)

Nested ng-repeat and radio or checkbox inputs not working

I am trying to show list of questions and their choices by nested ng-repeat, I have seen plenty of similar questions but still could not fix my issue. My issue here is I could see the list of questions but the choices are not getting displayed and in the developer tools I could only see the commented ng-repeat line in place of choices.
Here is my View
<div ng-repeat ="question in questions track by $index" class="panel panel-default" ng-show="showQuestions">
<div class="panel-heading">
<div class="panel-title">
<a href="div#{{$index}}" class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" >
{{question.QuestionTxt}}
</a>
<div class="row height"></div>
<div class="row" ng-show="question.QuestionTypeTxt == 'RadioButton'">
<div class="col-xs-3" ng-repeat ="answer in questions.QuestionAnswers track by $index">
<input type="radio" ng-model="selectedChoice.choice" ng-value="{{answer.AnswerTxt}}" name="{{question.QuestionTxt}}"/>{{answer.AnswerTxt}}
</div>
</div>
<div class="row" ng-show="question.QuestionTypeTxt == 'Checkbox'">
<div class="col-xs-3" ng-repeat ="answer in questions.QuestionAnswers track by $index">
<input type="checkbox" ng-model="selectedChoice.choice" ng-value="{{answer.AnswerTxt}}" name="{{question.QuestionTxt}}"/>{{answer.AnswerTxt}}
</div>
</div>
</div>
</div>
</div>
Here is my Controller
$scope.questions = [];
$scope.selectedChoice = { choice:"" };
$scope.addQuestions = function () {
$scope.showQuestions = true;
rmat3Service.getQuestionsForSection().then(function (data) {
angular.forEach(data,function(a) {
$scope.questions.push(a);
});
});
}
This is my Json data:
var questions = new List<Question>();
var answers = new List<QuestionAnswer>();
answers.Add(new QuestionAnswer()
{
AnswerTxt = "Yes",
});
answers.Add(new QuestionAnswer()
{
AnswerTxt = "No"
});
answers.Add(new QuestionAnswer()
{
AnswerTxt = "Yes Verified"
});
answers.Add(new QuestionAnswer()
{
AnswerTxt = "Not Applicable"
});
questions.Add(new Question()
{
QuestionId = 1,
QuestionTxt = "Are aisles clear of product on the floor?",
QuestionTypeTxt = "RadioButton",
QuestionAnswers = answers
});
questions.Add(new Question()
{
QuestionId = 2,
QuestionTxt = "Automated Car Wash",
QuestionTypeTxt = "Checkbox",
QuestionAnswers = answers
});
return Json(questions, JsonRequestBehavior.AllowGet);
The issue is that you're attempting to loop questions.QuestionAnswers which doesn't exist. It should be question.QuestionAnswers:
<div class="col-xs-3" ng-repeat ="answer in question.QuestionAnswers track by $index">

Angular filter results when user clicks on repeat

I am trying to create an Angular filter that allows users to click on a record and have the filter then show only that one record within the same repeater.
For example, when a person searches for last name "knight," they see some results. Then, when the user clicks on the specific record they want, they should see only that one record displaying in the repeater.
My html is this:
<md-list-item class="md-3-line" ng-repeat="value in ctrl.results" ng-click="ctrl.showRecord(value)">
<div class="md-list-item-text" layout="column">
<h4>Employee Id: <b>{{ value.employeeId }}</b></h4>
<h4>NetId: <b>{{ value.netId }}</b></h4>
<p>Name: {{ value.preferredFirstName }} {{ value.preferredLastName }}</p>
</div>
</md-list-item>
and it passes the selected record to my controller in this function:
vm.showRecord = function (selectedRecord, ev) {
//need my filter here
};
I have looked over a number of the examples on filters, but I don't quite see how to make the filter update the very same repeat that the user clicked on.
** Edit to show answer based on Tom Chen's work **
For anyone doing this with controller as syntax, here is the answer.
html:
<md-list-item class="md-3-line" ng-repeat="value in ctrl.results | filter:ctrl.selectedId" ng-click="ctrl.showRecord(value.employeeId)">
<div class="md-list-item-text" layout="column">
<h4>Employee Id: <b>{{ value.employeeId }}</b></h4>
<h4>NetId: <b>{{ value.netId }}</b></h4>
<p>Name: {{ value.preferredFirstName }} {{ value.preferredLastName }}</p>
</div>
</md-list-item>
controller:
vm.showRecord = function (selectedRecord) {
vm.selectedId = selectedRecord;
};
You can achieve this simply by using angular filter expression like this:
<md-list-item class="md-3-line" ng-repeat="value in ctrl.results | filter:vm.selectedId" ng-click="ctrl.showRecord(value.employeeId)">
<div class="md-list-item-text" layout="column">
<h4>Employee Id: <b>{{ value.employeeId }}</b></h4>
<h4>NetId: <b>{{ value.netId }}</b></h4>
<p>Name: {{ value.preferredFirstName }} {{ value.preferredLastName }}</p>
</div>
</md-list-item>
and in your controller :
vm.showRecord = function (id) {
vm.selectedId = id;
};
UPDATED ANSWER WITH WORKING EXAMPLE
Here is an example in Plunker
You could do it with an ng-if
<md-list-item ng-if="!ctrl.selectedRecord || ctrl.selectedRecord === value" ng-repeat="value in ctrl.results" ng-click="ctrl.showRecord(value)">
...
</md-list-item>
JS
vm.showRecord = function (selectedRecord, ev) {
//if the record is already selected toggel it off
if(vm.selectedRecord === selectedRecord) {
vm.selectedRecord = undefined;
} else {
vm.selectedRecord = selectedRecord
}
};

How to get dynamic ng-model from ng-repeat in javascript?

I'm developoing a web app and stuck here:
Part of the HTML:
<div class="input-group">
<select name="select" class="form-control input-group-select" ng-options="key as key for (key , value) in pos" ng-model="word.pos" ng-change="addPos()">
<option value="">Choose a POS</option>
</select>
<span class="sort"><i class="fa fa-sort"></i></span>
</div>
<ul class="listGroup" ng-show="_pos.length > 0">
<li class="list" ng-repeat="item in _pos track by $index">
<span>
{{item.pos}}
<span class="btn btn-danger btn-xs" ng-click="delPos($index)">
<span class="fa fa-close"></span>
</span>
</span>
<!-- I wanna add the input which can add more list item to the item.pos-->
<div class="input-group">
<a class="input-group-addon add" ng-class=" word.newWordExp ? 'active' : ''" ng-click="addItemOne()"><span class="fa fa-plus"></span></a>
<input type="text" class="form-control exp" autocomplete="off" placeholder="Add explanation" ng-model="word.newWordExp" ng-enter="addExpToPos()">
{{word.newWordExp}}
</div>
</li>
</ul>
Part of the js:
$scope._pos = [];
$scope.addPos = function () {
console.log("You selected something!");
if ($scope.word.pos) {
$scope._pos.push({
pos : $scope.word.pos
});
}
console.dir($scope._pos);
//console.dir($scope.word.newWordExp[posItem]);
};
$scope.delPos = function ($index) {
console.log("You deleted a POS");
$scope._pos.splice($index, 1);
console.dir($scope._pos);
};
$scope.addItemOne = function (index) {
//$scope.itemOne = $scope.newWordExp;
if ($scope.word.newWordExp) {
console.log("TRUE");
$scope._newWordExp.push({
content: $scope.word.newWordExp
});
console.dir($scope._newWordExp);
$scope.word.newWordExp = '';
} else {
console.log("FALSE");
}
};
$scope.deleteItemOne = function ($index) {
$scope._newWordExp.splice($index, 1);
};
So, what am I wannt to do is select one option and append the value to $scope._pos, then display as a list with all of my selection.
And in every list item, add an input filed and add sub list to the $scope._pos value.
n.
explanation 1
explanation 2
explanation 3
adv.
explanation 1
explanation 2
So I don't know how to generate dynamic ng-model and use the value in javascript.
Normaly should like ng-model="word.newExplanation[item]" in HTML, but in javascript, $scope.word.newExplanation[item] said "item is not defined".
can any one help?
If I've understood it correclty you could do it like this:
Store your lists in an array of object this.lists.
The first object in the explanation array is initialized with empty strings so ng-repeat will render the first explanation form.
Then loop over it with ng-repeat. There you can also add dynamically the adding form for your explanation items.
You can also create append/delete/edit buttons inside the nested ng-repeat of your explanation array. Append & delete is already added in the demo.
Please find the demo below or in this jsfiddle.
angular.module('demoApp', [])
.controller('appController', AppController);
function AppController($filter) {
var vm = this,
explainTmpl = {
name: '',
text: ''
},
findInList = function (explain) {
return $filter('filter')(vm.lists, {
explanations: explain
})[0];
};
this.options = [{
name: 'option1',
value: 0
}, {
name: 'option2',
value: 1
}, {
name: 'option3',
value: 2
}];
this.lists = [];
this.selectedOption = this.options[0];
this.addList = function (name, option) {
var list = $filter('filter')(vm.lists, {
name: name
}); // is it in list?
console.log(name, option, list, list.length == 0);
//vm.lists
if (!list.length) {
vm.lists.push({
name: name,
option: option,
explanations: [angular.copy(explainTmpl)]
});
}
};
this.append = function (explain) {
console.log(explain, $filter('filter')(vm.lists, {
explanations: explain
}));
var currentList = findInList(explain);
currentList.explanations.push(angular.copy(explainTmpl));
}
this.delete = function (explain) {
console.log(explain);
var currentList = findInList(explain),
index = currentList.explanations.indexOf(explain);
if (index == 0 && currentList.explanations.length == 1) {
// show alert later, can't delete first element if size == 1
return;
}
currentList.explanations.splice(index, 1);
};
}
AppController.$inject = ['$filter'];
<link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="appController as ctrl">
<select ng-model="ctrl.selectedOption" ng-options="option.name for option in ctrl.options"></select>
<input ng-model="ctrl.listName" placeholder="add list name" />
<button class="btn btn-default" title="add list" ng-click="ctrl.addList(ctrl.listName, ctrl.selectedOption)"><i class="fa fa-plus"></i>
</button>
<div class="list-group">Debug output - current lists:<pre>{{ctrl.lists|json:2}}</pre>
<div class="list-group-item" ng-repeat="list in ctrl.lists">
<h2>Explanations of list - {{list.name}}</h2>
<h3>Selected option is: {{ctrl.selectedOption}}</h3>
<div class="list-group" ng-repeat="explain in list.explanations">
<div class="list-group-item">
<p class="alert" ng-if="!explain.title">No explanation here yet.</p>
<div class="well" ng-if="explain.title || explain.text">
<h4>
{{explain.title}}
</h4>
<p>{{explain.text}}</p>
</div>Title:
<input ng-model="explain.title" placeholder="add title" />Text:
<input ng-model="explain.text" placeholder="enter text" />
<button class="btn btn-primary" ng-click="ctrl.append(explain)">Append</button>
<button class="btn btn-primary" ng-click="ctrl.delete(explain)">Delete</button>
</div>
</div>
</div>
</div>
</div>

Get data, change one single element and return to api

I get Data from an api and easily list them, now i want to change one element of those, to "default". I dont know how to control that,
Here is the js.
$scope.updateDefault = function() {
if (AuthService.isAuth()) {
Account.one().get().then(
function(account) {
**account.data.defaultMsisdn= $scope.element.isSelected;
$log.d("account: ", account.data);
account.data.put();**
}
);
}
};
here is the HTML:
<div id="container" style="width:650px">
<ol ng-repeat="element in accountmsisdn">
**<li style=" text-align:left; float:left">
<input type="radio" ng-model="element.isSelected" ng-click="updateDefault()">
<span>{{element.msisdn}} </span>
</li>**
<li style="text-align:center;float: inside" ng-switch="element.active">
<span ng-switch-when=true>
{{'view.settings.sender.active'| translate}}</span>
<span ng-switch-when=false>
{{'view.settings.sender.notactive'| translate}}</span>
<span ng-switch-default>
<strong> - </strong> </span>
</li>
You need to pass the current element as an argument to updateDefault(), so it knows what element to update:
<input type="radio" ng-model="element.isSelected" ng-click="updateDefault(element)" />
$scope.updateDefault = function (element) {
...
account.data.defaultMsisdn = element.isSelected;
..
};

Resources