Directive Does Not Inherit Controller's Scope - javascript

I have a controller set up which contains a few functions to do form validation. In this controllers $scope I have an array $scope.errorMsgs that is populated with strings of error messages the user makes when filling out the form.
I also have a directive that displays this form. They are both attached to the same module. The controller and directive are in separate files within the same directory. However the scope in the directive's link function does not reference the $scope in the controller. They have different $ids in fact. Any ideas as to why this is happening?
Module:
angular.module('aop.availabilitysolver', [
'aop.services',
'checklist-model'
]).run(['widgetService', function(widgetService) { 'use strict';
widgetService.registerWidgets([
{
title: 'AVAILABILITYSOLVER.WIDGETS.AVAILABILITYSOLVER',
translatableDescription: 'AVAILABILITYSOLVER.WIDGETS.AVAILABILITYSOLVER',
type: 'aop-availability-solver',
configuration: {},
width: 1
}
]);
}]);
Controller
angular.module('aop.availabilitysolver')
.controller('AvailabilitySolverController', ['$scope',
function ($scope) { 'use strict';
//console.log($scope);
$scope.selectGoalDropdown = ['Impressions', 'Spend'];
$scope.selectGoalTimespan = ['Day', 'Week', 'Month'];
$scope.selectGoals = [
{
id: '1',
name: 'Impressions'
},
{
id: '2',
name: 'Spend'
}
];
$scope.selectTimespan = [
{
id: '4',
name: 'Day'
},
{
id: '5',
name: 'Week'
},
{
id: '6',
name: 'Month'
}
];
$scope.selectedItem = 'test2';
$scope.selectedItem1 = 'test3';
$scope.per = [1, 2, 3, 4, 5, 6, 10, 12, 15, 20];
$scope.hours = [1, 3, 4, 12, 24, 36, 48, 72, 120, 168];
$scope.uncpd = ['uncapped'];
$scope.times = {
amt: [],
freq: [],
uncapped: []
};
$scope.caps = [];
$scope.quantity;
$scope.level = 'Fcap';
$scope.showErrors = false;
$scope.errorMsgs = [];
$scope.calculateFreqCaps = function(amt, freq, uncap) {
var rtn = [];
function isNothingSelected() { // No selections made
if(amt.length === 0 && freq.length === 0 && uncap.length === 0) {
rtn.push('Please choose frequency settings or select \'uncapped.\'');
$scope.errorMsgs.push('Please choose frequency settings or select \'uncapped.\'');
}
}
function malformedFrequencyOpts() { // Selected amount but no frequency & vice versa
if((amt.length > 0 && freq.length === 0) || (amt.length === 0 && freq.length > 0)) {
rtn.push('Please select both an amount and a frequency.');
$scope.errorMsgs.push('Please select both an amount and a frequency.');
}
}
function selectedTooMuch() { // Uncapped and frequency settings selected
if((amt.length > 0 || freq.length > 0) && uncap.length === 1) {
rtn.push('Choose uncapped only if no amount or frequency is selected');
$scope.errorMsgs.push('Choose uncapped only if no amount or frequency is selected');
}
}
isNothingSelected();
malformedFrequencyOpts();
selectedTooMuch();
if(rtn.length > 0) {
return rtn;
} else if (amt.length === 0 && freq.length === 0 && uncap.length === 1) { // Only uncapped selected
return ['uncapped'];
}
angular.forEach(amt, function (a) {
angular.forEach(freq, function (f) {
rtn.push(a + '/' + f + 'h');
});
});
return rtn;
};
$scope.validateSelectGoalQuantity = function(n) {
if(!Number(n)) {
$scope.errorMsgs.push('Quantity must be a number');
return false;
}
return true;
};
$scope.submitBtnClick = function() {
// Build Frequency cap JSON object
$scope.caps = $scope.calculateFreqCaps($scope.times.amt, $scope.times.freq, $scope.times.uncapped);
$scope.validateSelectGoalQuantity($scope.quantity);
if($scope.errorMsgs.length > 0) {
console.log($scope.errorMsgs);
// Show error message div and clear $scope.errorMsgs
$scope.showErrors = true;
//$scope.errorMsgs.length = 0;
}
else {
$scope.showErrors = false;
}
};
}]);
Directive
angular.module('aop.availabilitysolver')
.directive('aopAvailabilitySolver', ['$filter', function($filter) { 'use strict';
return {
restrict: 'E',
link: function(scope, element, attrs) {
angular.noop(attrs);
// Hide error div initially
$('.availabilitySolverErrorDisplay').hide();
var i = element.find('.levelRadio :radio');
i.on('click', function() {
if($(i[0]).prop('checked')) {
scope.level = 'Fcap';
element.find('.freqCapDiv').show();
}
else {
scope.level = 'Bid';
element.find('.freqCapDiv').hide();
}
});
console.log(scope);
},
templateUrl: 'features/availabilitySolver/availabilitySolver.html'
};
}]);
HTML
<div ng-controller="AvailabilitySolverController">
<div class="container-fluid availabilitySolverScreen1">
<div class="row">
<div class="alert alert-danger availabilitySolverErrorDisplay">
</div>
</div>
<div class="row">
Campaign Selector
</div>
<!-- Goals -->
<div class="row">
<h5>Select Goal</h5>
<form name="selectGoalForm" novalidate>
<div class="col-md-4">
<button name="goals" class="btn btn-default" ng-model="selectedItem" ng-options="value.id as value.name for (key, value) in selectGoals" data-style="btn-primary" bs-select></button>
</div>
<div class="col-md-4">
<div class="col-md-10">
<input type="number" name="quantity" class="form-control" placeholder="Quantity" ng-model="quantity">
</div>
<div class="col-md-2">
per
</div>
</div>
<div class="col-md-4">
<button name="timespan" class="btn btn-default" ng-model="selectedItem1" ng-options="value.id as value.name for (key, value) in selectTimespan" data-style="btn-primary" bs-select></button>
</div>
</form>
</div><!-- End goals -->
<!-- Level cap -->
<div class="row">
<h5>Level</h5>
<div class="col-md-12">
<form class="levelRadio">
<input name="level" value="Fcap" type="radio" checked> Fcap
<input name="level" value="Bid" type="radio"> Bid
</form>
</div>
</div><!-- end level cap -->
<!-- Frequency cap analysis -->
<div class="row freqCapDiv">
<h5>Customize Frequency Cap for Analysis</h5>
<div class="col-md-8">
<!-- per -->
<div class="col-md-4">
<ul>
<li ng-repeat="item in per">
<input type="checkbox"
checklist-value="item"
checklist-model="times.amt" /> {{item}} per
</li>
</ul>
</div><!-- end per -->
<!-- hour(s) -->
<div class="col-md-4">
<ul>
<li ng-repeat="item in hours">
<input type="checkbox"
checklist-value="item"
checklist-model="times.freq" /> {{item}} hr
</li>
</ul>
</div>
<!-- uncapped -->
<div class="col-md-4">
<ul>
<li ng-repeat="item in uncpd">
<input type="checkbox"
checklist-value="item"
checklist-model="times.uncapped" /> uncapped
</ul>
</div>
</div>
<div class="col-md-4">
</div>
</div><!-- end frequency cap analysis -->
<!-- submit button -->
<div class="row">
<button class="btn btn-primary" ng-click="submitBtnClick()">Submit</button>
</div>
</div>
</div>

Related

Unable to dynamically filter with AngularJS

I am trying to dynamically filter in my html. When I search for CMS, I need the number on the left panel to update to '1' for both Performance and Investments. I also need the applet to display on the right panel.
(With my current code I am able to display the applets only when I have a category selected, and does not update the number on the left panel)
Image
Can anyone help me better understand what I am missing here? Any help would be much appreciated!
My data:
$scope.categories = [
{
'name': 'Performance',
'applets': ['CMS', 'Performance Snapshot']
},
{
'name' : 'Investments',
'applets' : ['Commitment Widget', 'CMS']
},
{
'name' : 'Operations',
'applets' : []
}
]
controller:
$scope.categories = categories;
$scope.chooseCategory = function(category) {
$scope.selectedCategoryApplets = category.applets;
}
html:
<div id="app">
<h1>Library</h1>
<div ng-controller="MainCtrl" class="container">
<div class="row">
<div class="col-sm-4">
<h4>Categories</h4>
<input type="text" value="searchText" ng-model="searchText" placeholder="Search Applets" />
<div ng-repeat="category in categories | filter: searchText" ng-click="chooseCategory(category)">
<div>{{category.name}}<span>{{category.applets.length}}</span></div>
</div>
</div>
</div>
<div class="col-sm-8">
<h3>Applets</h3>
<div ng-repeat="value in selectedCategoryApplets | filter: searchText">
{{value}}
</div>
</div>
</div>
</div>
You should have a different variable for displaying the filtered result.
JS:
$scope.filteredCategories = $scope.categories;
$scope.filterBySearchText = function(searchText) {
if (searchText === undefined || searchText.trim() === "") {
$scope.filteredCategories = $scope.categories;
return;
}
$scope.filteredCategories = angular.copy($scope.categories).map(cat => {
cat.applets = cat.applets.filter(
app => app.indexOf(searchText) !== -1
);
return cat;
});
};
HTML:
<div class="row">
<div class="col-sm-4">
<h4>Categories</h4>
<input type="text" value="searchText" ng-model="searchText" placeholder="Search Applets" ng-change="filterBySearchText(searchText)"/>
<div ng-repeat="category in filteredCategories" ng-click="chooseCategory(category)">
<div>{{category.name}}<span>{{category.applets.length}}</span></div>
</div>
</div>
</div>
<div class="col-sm-8">
<h3>Applets</h3>
<div ng-repeat="value in selectedCategoryApplets | filter: searchText">
{{value}}
</div>
</div>
https://stackblitz.com/edit/angularjs-nxwvce
Controller:
$scope.filter = function() {
$timeout(function() {
$scope.filteredItems = $scope.filtered.length;
}, 10);
};
$scope.sort_by = function(predicate) {
$scope.predicate = predicate;
$scope.reverse = !$scope.reverse;
};
HTML:
Input element used for filter
<div>
Filter
<i class="fa fa-filter" aria-hidden="true"></i>
</div>
<input type="text" ng-model="search" ng-change="filter()" placeholder="Filter" class="form-control" />
<div> where data is getting filtered
<div ng-repeat="item in filtered = (list | filter:search | orderBy : predicate :reverse) | startFrom:(currentPage-1)*entryLimit | limitTo:entryLimit">
......
</div>
Hope this works!!

check duplicates from the list and show error messge

Plunkr
From the above example, Created a list and the list will be in editable mode on click edit button.
It is created using angular-xeditable.
From the list, just want to check the duplicates and show an error message if it matches.
The below code able to find the duplicates and shows an error. But, if the two or more values has the same name. the following error happens.
If the changes has done in any of them then other value of the error
messages remain the same.
The error messages is not hiding on click the delete button (x).
Thanks in advance.
scripts.js
var app = angular.module('app', ['ngRoute', 'xeditable']);
app.controller('indexController', ['$scope', '$http', function ($scope, $http) {
$scope.showIcons = false;
$scope.newVal = "";
$scope.noPossValues = false;
$scope.getParamInfo = function (id) {
if (id !== undefined) {
$http.get('./getparameterbyid.json').success(function (data) {
if (data.param_values.length == 0)
$scope.noPossValues = true;
$scope.paraInfo = data;
}).error(function (err) {
console.log("Err : ", err);
});
}
};
$scope.addNewValue = function (val, id) {
$scope.paraInfo.param_values.push({
value: $scope.newVal,
default_value: null,
operation: null
});
$scope.newVal = "";
$scope.noPossValues = false;
};
$scope.updatedPossValue = function (val, index) {
var values = [];
input = val.toLowerCase();
$scope.paraInfo.param_values.map(function (item, i) {
if (val == "" && index == i) {
item.error_msg = true;
}
if (val != "" && index == i) {
item.error_msg = false;
}
if (item.operation == null)
values.push(item.value.toLowerCase());
if (index == i) {
item.value = val;
}
});
if (values.indexOf(input) > -1) {
$scope.paraInfo.param_values.map(function (item, i) {
if (item.operation == null) {
if (item.value.toLowerCase() == input) {
item.dup_item = true;
} else {
item.dup_item = false;
}
}
})
} else {
$scope.paraInfo.param_values[index].dup_item = false;
}
};
$scope.removePossVal = function (id) {
var deleteCount = 0,
nullCount = 0;
var indexOfItem = $scope.paraInfo.param_values.indexOf($scope.paraInfo.param_values[id]);
$scope.paraInfo.param_values[indexOfItem].operation = "delete";
$scope.paraInfo.param_values.map(function (item, index) {
if (item.error_msg != undefined && index == id)
delete item.error_msg;
if (item.operation == null)
nullCount += 1;
if (item.operation == "delete")
deleteCount += 1;
});
if (deleteCount == $scope.paraInfo.param_values.length) {
$scope.showIcons = true;
$scope.noPossValues = true;
}
};
$scope.enableEdit = function (action) {
if (action != 'cancel' || action != 'submit')
$scope.showIcons = !$scope.showIcons;
};
$scope.submitParameter = function () {
$scope.enableEdit();
};
$scope.editableParameter = function () {
$scope.tableform.$show();
$scope.enableEdit();
};
$scope.cancelParameter = function () {
if ($scope.showIcons == true)
$scope.enableEdit('cancel');
};
}]);
index.html
<!DOCTYPE html>
<html>
<head>
<!-- Stylesheet -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="http://vitalets.github.io/angular-xeditable/starter/angular-xeditable/css/xeditable.css" rel="stylesheet">
<!-- scripts-->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous">
</script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
crossorigin="anonymous">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular-route.min.js">
</script>
<script src="http://vitalets.github.io/angular-xeditable/starter/angular-xeditable/js/xeditable.js">
</script>
<script src="script.js">
</script>
</head>
<body ng-app="app" ng-controller="indexController">
<div class="container mt-5">
<form action="" editable-form name="tableform" onaftersave="submitParameter()" oncancel="cancelParameter()">
<div ng-init="getParamInfo('10')">
<button type="button" class="btn btn-primary pull-right cur-point mb-3" ng-show="!tableform.$visible"
ng-click="editableParameter()">
<i class="fa fa-pencil"></i> Edit Fields
</button>
<div class="form-group row text-center">
<label for="colFormLabel" class="col-sm-5 m-1 col-form-label">Possible Values : </label>
<div class="col-sm-6">
<div style="display: flex;">
<div class="card" style="width: 70%; min-height: 2.5rem; margin: 0 auto;" ng-hide="noPossValues">
<ul class="list-group list-group-flush" ng-repeat="(index, pv) in paraInfo.param_values">
<li style="padding: 0.44rem;" class="list-group-item" ng-show="!showIcons && pv.value != undefined && pv.operation != 'delete'">{{pv.value}}</li>
<div class="input-group" ng-show="showIcons && pv.value != undefined && pv.operation != 'delete'">
<input type="text" class="form-control rounded-0" ng-class="updateVal == '' ? 'has-error no-border-color' : ''"
ng-value="pv.value" ng-model="updateVal" ng-change="updatedPossValue(updateVal, index)">
<span class="input-group-btn" style="border-bottom: 2px solid rgba(0,0,0,.15);"
ng-class="updateVal == '' ? 'has-error' : ''">
<a class="btn btn-danger rounded-0 cur-pointer text-white" ng-click="removePossVal(index)">
<i class="fa fa-remove"></i>
</a>
</span>
</div>
<span class="text-danger text-left" ng-show="pv.error_msg">No empty values</span>
<span class="text-danger param-poss-values" ng-show="pv.dup_item">No duplicate values</span>
</ul>
</div>
<div ng-show="noPossValues && showIcons" class="d-flex">
<input type="text" class="form-control add-new-inp-txt" ng-model="newVal" placeholder="Add new...">
<button class="btn btn-info cur-pointer text-white add-new-btn" ng-click="addNewValue(newVal)"
ng-disabled="newVal == ''">
<i class="fa fa-plus"></i>
</button>
</div>
</div>
</div>
</div>
<div class="form-group row" ng-show="showIcons && paraInfo.param_values.length > 0 && !noPossValues">
<label for="colFormLabel" class="col-sm-5 m-1 col-form-label : "></label>
<div class="col-sm-6 text-center">
<div style="display: flex; width: 70%; margin-left: 15%;">
<input type="text" name="pincode" ng-pattern="patternValueBox" class="form-control add-new-inp-txt"
ng-model="newVal" ng-change="checkDuplicateValue(newVal)" placeholder="Add new...">
<button class="btn btn-info cur-pointer text-white add-new-btn" ng-click="addNewValue(newVal)"
ng-disabled="newVal == '' || duplicateValue">
<i class="fa fa-plus"></i>
</button>
<span class="text-danger param-poss-values" ng-show="duplicateValue">No duplicate
values</span>
</div>
</div>
</div>
<div class="text-center mt-5 row" ng-show="tableform.$visible">
<div class="col-md-4">
<button type="button" ng-disabled="tableform.$waiting" ng-click="tableform.$cancel()" class="btn btn-outline-secondary mr-3 cur-point">Cancel</button>
</div>
<div class="col-md-4">
<button type="submit" class="col-sm-7 btn btn-outline-success mr-3 ml-3 cur-point" ng-disabled="updateVal == ''">Submit{{updateVal}}</button>
</div>
</div>
</div>
</form>
</div>
</body>
</html>
def FindDuplicates(in_list):
unique = set(in_list)
for each in unique:
count = in_list.count(each)
if count > 1:
print 'There are duplicates in this list'
return True
print 'There are no duplicates in this list'
return False
if name == 'main':
# test it
a = [8, 64, 16, 32, 4, 24]
b = [2,2,3,6,78,65,4,4,5]
FindDuplicates(a)
FindDuplicates(b)

Unable to load a Knockout Component - Unknown template value: [object Object]

This is how I am using the component and sending the parameters using a Custom Element:
<div class="container" data-bind="with: DevoteeList">
<div class="row" style="padding: 10px;">
<div class="col-md-8"></div>
<div class="col-md-4">
<ko-pager params="Data: Devotees,
Modifier: $parent.DevoteeModifier,
PageCount: DevoteesPageCount(),
Url: '#Url.Action("SelectDevotees", "Devotee", new { a = 1 })'"></ko-pager>
</div>
</div>
This is how I am defining a Knockout Component. It is a Pager that I want to use at few places. But, I am receiving the error: Uncaught Error: Unable to process binding "with: function (){return SelectDevotees }"
Message: Unable to process binding "with: function (){return DevoteeList }"
Message: Unable to process binding "component: function () { return l }"
Message: Component 'ko-pager': Unknown template value: [object Object]
ko.components.register('ko-pager', {
viewModel: function (params) {
var self = this;
self.currentPage = ko.observable(1);
self.pages = ko.observableArray([]);
self.PageCount = ko.observable(params.PageCount);
//self.currentPage.subscribe(function (nv) {
// self.GetPage(self.parent);
//});
self.GetPages = function () {
for (var i = 1; i <= params.PageCount ; i++) {
self.pages.push(i);
}
return self.pages;
};
self.FirstPage = function () {
self.GetPage(1);
};
self.PrevPage = function () {
if (self.currentPage() > 1) {
var pn = self.currentPage() - 1;
self.GetPage(pn);
}
};
self.LastPage = function () {
self.GetPage(params.PageCount);
};
self.NextPage = function () {
if (self.currentPage() < params.PageCount) {
var pn = self.currentPage() + 1;
self.GetPage(pn);
}
};
self.GetPage = function (pg) {
if (pg == null)
pg = self.currentPage();
else
self.currentPage(pg);
var url = params.Url + '&pageNumber=' + pg;
$.get(url, function (data) {
var t = ko.mapping.fromJS(data);
if (params.Modifier) {
params.Modifier(t);
}
params.Data(t());
});
};
},
template: { element: document.getElementById('ko-ajax-pager') }
});
<div id="ko-ajax-pager" style="display: none;">
<div class="row" style="padding: 10px;" data-bind="visible: PageCount > 1">
<div class="col-md-1"></div>
<div class="col-md-2">
<input type="button" value="First" class="btn" data-bind="click: FirstPage" />
</div>
<div class="col-md-2">
<input type="button" value="Prev" class="btn" data-bind="click: PrevPage" />
</div>
<div class="col-md-2">
<select data-bind="options: GetPages(), value: currentPage, event: { change: GetPage(null) }">
</select>
</div>
<div class="col-md-2">
<input type="button" value="Next" class="btn" data-bind="click: NextPage" />
</div>
<div class="col-md-2">
<input type="button" value="Last" class="btn" data-bind="click: LastPage" />
</div>
<div class="col-md-1"></div>
</div>
</div>
Can someone please figure out, what is wrong?

Angular JS Filter - Filter by 3 checkboxes

I have a sales array and I want to filter by the status of the sale action (finished, pending or/and failed). What I am trying is to show entire list, and unchecking the checkboxes some rows will disapear.
HTML Code
<div class="row" ng-repeat="sale in salesArray | filter: okStatus | filter: pendingStatus | filter: failedStatus">
<div class="col-lg-1 col-md-1 col-sm-1 col-xs-1">
<i ng-class="'icon ' + sale.icon + ( sale.status == 'ok' ? ' text-green' : (sale.status == 'pending' ? ' text-amber' : ' text-red') )"></i>
</div>
<div class="col-lg-2 col-md-2 col-sm-2 col-xs-2">
<|sale.user|>
</div>
<div class="col-lg-3 col-md-3 col-sm-3 col-xs-3">
<|sale.product|>
</div>
<div class="col-lg-2 col-md-2 col-sm-2 col-xs-2">
<|sale.price | currency:"$"|>
</div>
<div class="col-lg-2 col-md-2 col-sm-2 col-xs-2">
<|sale.date|>
</div>
<div class="col-lg-2 col-md-2 col-sm-2 col-xs-2">
</div>
</div>
<ul class="justified-list">
<li>
<div class="checkboxer checkboxer-green form-inline">
<input type="checkbox" id="checkboxColor10" ng-model="okStatus" ng-value="ok">
<label for="checkboxColor10">Finalizados (<|(salesArray | filter: {status: 'ok'}).length|>)</label>
</div>
</li>
<li>
<div class="checkboxer checkboxer-amber form-inline">
<input type="checkbox" id="checkboxColor14" ng-model="pendingStatus" ng-value="pending">
<label for="checkboxColor14">En proceso (<|(salesArray | filter: {status: 'pending'}).length|>)</label>
</div>
</li>
<li>
<div class="checkboxer checkboxer-red form-inline">
<input type="checkbox" id="checkboxColor1" ng-model="failedStatus" ng-value="failed">
<label for="checkboxColor1">Abortados (<|(salesArray | filter: {status: 'failed'}).length|>)</label>
</div>
</li>
</ul>
Controller Code:
$scope.okStatus = "";
$scope.pendingStatus = "";
$scope.failedStatus = "";
$scope.salesArray = [
{icon: "ion-checkmark-round", user: "Jtd", price: 123.32, product: "Sesión de una hora", date: "12/02/2015", status: "ok"},
{icon: "ion-close-round", user: "Tar", price: 53.00, product: "Sesión de media hora", date: "14/02/2016", status: "failed"},
{icon: "ion-compass", user: "Rao", price: 103.90, product: "Sesión de 45 minutos", date: "15/03/2016", status: "pending"}
];
How can I get this filter? Is obvious now it is not working
I combined knowledge from several other SO questions to suggest a solution:
Bind all checkboxes to a single model
Use a custom filter to filter the sales according to the checkboxes model
The solution can look like this (better to look at the plunkr):
HTML
<body ng-app="app" ng-controller="ctrl">
<label ng-repeat="status in statuses">
<input
type="checkbox"
name="selectedStatuses[]"
value="{{status}}"
ng-checked="selection.indexOf(status) > -1"
ng-click="toggleSelection(status)"
> {{status}}
</label>
<div ng-repeat="sale in salesArray | selectedFilter:selection">{{ sale.user }} | {{sale.product}} | {{sale.status}}</div>
</body>
JS
app = angular.module('app', []);
app.filter('selectedFilter', function() {
return function(items, options) {
var filtered = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (options.indexOf(item.status) != -1) {
filtered.push(item);
}
}
return filtered;
};
});
app.controller('ctrl', ['$scope', function($scope) {
$scope.statuses = ['ok', 'pending', 'failed'];
$scope.selection = ['ok', 'pending', 'failed'];
// toggle selection for a given fruit by name
$scope.toggleSelection = function toggleSelection(status) {
var idx = $scope.selection.indexOf(status);
// is currently selected
if (idx > -1) {
$scope.selection.splice(idx, 1);
}
// is newly selected
else {
$scope.selection.push(status);
}
};
$scope.salesArray = [{
icon: "ion-checkmark-round",
user: "Jtd",
price: 123.32,
product: "Sesión de una hora",
date: "12/02/2015",
status: "ok"
}, {
icon: "ion-close-round",
user: "Tar",
price: 53.00,
product: "Sesión de media hora",
date: "14/02/2016",
status: "failed"
}, {
icon: "ion-compass",
user: "Rao",
price: 103.90,
product: "Sesión de 45 minutos",
date: "15/03/2016",
status: "pending"
}];
}]);
if the value of the ng-class is expression, then it should be placed {}.
Make it like switch case. For example 'class to be applied':'the condition' with separated commas as shown below..
HTML Code:
<i ng-class="{'text-green':(sale.status == 'ok'),'
text-amber':(sale.status == 'pending'), 'text-red':(sale.status != 'pending')}"></i>
The logic be could written in function and the method could be called similar to below. Ensure construct the return structure as you want.
HTML Code:
<i ng-class="getDisplayClass(sale.icon, sale.status)"></i>
Controller Code:
$scope.getDisplayClass = function(saleicon, status) {
if (status == 'ok')
return 'icon' + saleicon + 'text-green';
else if (status == 'pending')
return 'icon' + saleicon + 'icon text-amber';
else
return 'icon' + saleicon + 'icon text-red';
}

Vue.js Todo task with CSS animation and transition effect

How do you add a visual indicator such as a spinner and a tick when you save a new task in the example below.
Basically when I click the save button the following should happen:
Save button should become invisible
Cancel icon should become invisible, a spinner should appear instead to indicate something is happening
A tick icon should briefly appear if successfully saved and then disappear before displaying the delete icon.
The v-show that i'm using doesn't seem to work when I try to replicate a sleep effect to display the spinner when the updateTask() method is fired?
<div class="container" id="el">
<div class="row">
<div class="col-md-10"><h1>Tasks</h1></div>
<div class="col-md-2">
<button id="" class="btn btn-primary pull-right" type="button" v-on:click="createTask()">
Add New
</button>
</div>
</div>
<div class="row" >
<div class="col-sm-10 col-md-8">
<table class="table table-striped">
<tr class="row" v-for="task in tasks">
<td class="col-sm-5">
<div class="form-group">
<label class="sr-only" for="name">
Name</label>
<input v-if="editKey == task.id" name="name" type="text" class="form-control" v-model="task.name">
<span v-else v-on:click="editTask(task)">{{ task.name }}</span>
</div>
</td>
<td class="col-sm-5">
<div class="form-group">
<label class="sr-only" for="date">
Date</label>
<input v-if="editKey == task.id" name="date" type="text" class="form-control date-picker" v-pikaday="task.date">
<span v-else v-on:click="editTask(task)">{{ task.date }}</span>
</div>
</td>
<td class="col-sm-2">
<ul class="list-inline">
<li v-if="editKey == task.id" >
<button class="btn btn-success btn-sm" type="button" v-on:click="updateTask(task)" v-show="!loading">
Save
</button>
</li>
<li v-if="editKey == task.id ">
<span v-show="!loading"><i class="fa fa-times text-danger" v-on:click="cancelEdit(task)" title="Cancel"></i></span>
<span v-show="loading"> <i class="fa fa-spinner"></i></span>
</li>
<li v-if="editKey !== task.id">
<i class="fa fa-trash-o text-muted" v-on:click="removeTask(task)" title="Delete"></i>
</li>
<li v-if="editKey !== task.id && task.id == -1">
<i class="fa fa-exclamation-triangle text-warning" title="Unsaved"></i>
</li>
</ul>
</td>
</tr>
</table>
</div>
<pre>{{$data | json }}</pre>
</div>
</div>
<script>
Vue.directive('pikaday', {
twoWay: true,
bind: function () {
var self = this
$(this.el)
.pikaday({
format: 'D MMM YYYY',
defaultDate: moment().toDate()
})
.on('change', function () {
self.set(this.value)
})
},
update: function (value) {
$(this.el).val(value).trigger('change')
},
unbind: function () {
$(this.el).off().pikaday('destroy')
}
})
var vm = new Vue({
el: '#el',
data: {
editKey: '',
loading: false,
beforeEditCache: {
id: '',
name: '',
date: ''
},
editedTask: null,
tasks: [
{id: 1, name: 'Task A', date: '25 Dec 2015'},
{id: 2, name: 'Task B', date: '26 Dec 2015'}
]
},
methods: {
createTask: function() {
// if previously we were editing a task, lets cancel the edit
if (this.editedTask){
this.cancelEdit();
}
// add new task with id -1 to indicate it hasn't been persisted
this.tasks.push({
id: -1,
name: '',
date: ''
});
// set edit key
this.editKey = -1;
},
storeTask: function(task) {
// check if mandatory field completed
if (!task.name || !task.date) {
return;
}
// persist the task by generating valid id
task.id = Math.floor((Math.random() * 100) + 1);
},
editTask: function(task) {
// if we were previously editing a task and clicked on another to edit without saving, let cancel the edit
if (this.editedTask){
this.cancelEdit();
}
this.setBeforeEditCache(task);
this.editedTask = task;
this.editKey = task.id;
},
updateTask: function (task) {
// if its a new task
if (task.id == -1){
this.storeTask(task);
}
// otherwise we are editing an existing task
else {
if (!this.editedTask.name || !this.editedTask.date) {
return;
}
this.loading = true;
this.sleep(3000);
this.editedTask = null;
this.editKey = '';
this.loading = false;
}
},
cancelEdit: function (task = null) {
if (task && task.id == -1) {
this.removeTask(task);
}
else {
this.editedTask.name = this.beforeEditCache.name;
this.editedTask.date = this.beforeEditCache.date;
this.editedTask = null;
this.editKey = '';
}
},
removeTask: function(task) {
this.tasks.$remove(task);
},
setBeforeEditCache: function(task) {
this.beforeEditCache.id = task.id;
this.beforeEditCache.name = task.name;
this.beforeEditCache.date = task.date;
},
sleep: function(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
}
})
</script>
This is the fiddle https://jsfiddle.net/ozzii/6oe2k3py/
* UPDATE *
So I've managed to update this - see the new fiddle, to provide the functionality required. But it's a very messy solution - code is all over the place. Anyone know of a better/cleaner way to refactor and achieve the same functionality and perhaps provide a fade in/out affect to the tick when you save the element?
Here is the part about the sleep effect. You can use setTimeout and use the bind function to make sure the this context inside it is the Vue component.
this.loading = true;
setTimeout((function(){
this.editedTask = null;
this.editKey = '';
this.loading = false;
}).bind(this), 3000);

Categories

Resources