How update list in AngularJS? - javascript

I created one TODO List in AngularJS but I didn't finish the update function. I have some difficulty.
How do I create the update function?
Link: https://plnkr.co/edit/XfWoGVrEBqSl6as0JatS?p=preview
<ul class="list-todo">
<li ng-repeat="t in tasks track by $index">
<div class="row">
<div class="six columns">
<p>{{ t }}</p>
</div>
<div class="three columns">
<button class="button" ng-click="update()">update</button>
</div>
<div class="three columns">
<button class="button" ng-click="delete()">x</button>
</div>
</div>
</li>
</ul>
Angular Code:
angular.module('todoTest', [])
.controller('todoController', function($scope) {
$scope.tasks = [];
$scope.add = function() {
$scope.tasks.push($scope.dotask);
}
$scope.update = function(){
$apply.tasks.push($scope.dotask);
}
$scope.delete = function() {
$scope.tasks.splice(this.$index, 1);
}
})

If you want to update the value you have to pass as parameter the position of the task inside the tasks array ($index is the position):
<button class="button" ng-click="update($index)">update</button>
And then the update function would be:
$scope.update = function(index){
$scope.tasks[index] = $scope.dotask;
}
Is that what you needed?

Button for updating. Visible only while updating.
<div class="row">
<button type="submit" class="u-full-width button button-primary">Criar Tarefa</button>
<button ng-show="updateMode" ng-click="update()" type="button" class="u-full-width button button-primary">Update</button>
</div>
New update function.
$scope.update = function(index) {
if ($scope.updateMode) {
$scope.tasks[$scope.updateIndex] = $scope.dotask;
$scope.updateMode = false;
} else {
$scope.dotask = $scope.tasks[index];
$scope.updateMode = true;
$scope.updateIndex = index;
}
If you click update on the task it will make the big update button visible and bring the old todo to the input. After hitting the big update button the todo task will update.
Plunker

Related

Angular filter only on button click

I can't seem to get my filter to only execute on a button click, it executes the first time and then filters automatically based on whatever text is in the box. Can someone help me out?
<section class="searchField">
<input type="text" ng-model="searchTerm">
<button type="button" ng-click="search()">Search</button>
</section>
<section ng-show="!resultsHidden">
<div class="no-recipes" ng-hide="players.length">No results</div>
<article class="playerSearch" ng-repeat="player in players | filter: filter" ng-cloak>
<h2>
{{player.name}}
</h2>
</article>
</section>
Javascript:
$scope.myFilter = function (player) {
var found = [];
for(player in players) {
if (player.name === $scope.searchTerm || player.number === $scope.searchTerm){
found.push(player);
}
}
return found;
};
function search(){
$scope.filter = $scope.searched;
$scope.resultsHidden = false;
}
$scope.searched = function(player){
if (!$scope.searchTerm || (player.number == $scope.searchTerm || (player.name.toLowerCase().indexOf($scope.searchTerm.toLowerCase()) != -1))){
return true;
}
return false;
};
var app = angular.module("app",[])
app.controller('ctrl',['$scope', function($scope){
$scope.resultsHidden = false;
$scope.players = [
{"name": "alpha"},
{"name": "beta"},
{"name": "gama"}
];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<section class="searchField">
<input type="text" ng-model="searchTerm">
<button type="button" ng-click="filter = searchTerm;resultsHidden = !resultsHidden">Search</button>
</section>
<section ng-show="resultsHidden">
<div class="no-recipes" ng-hide="players.length">No results</div>
<article class="playerSearch" ng-repeat="player in players | filter:{name:filter}" ng-cloak>
<h2>
{{player.name}}
</h2>
</article>
</section>
</div>
try this
<button type="button" ng-click=" filter = searchTerm">Search</button>
First of all, you should create the filter like this:
angular.module('myApp')
.filter('my-filter', function( /* dependencies goes here */ ){
return function (input, isFilterActive) {
if (isFilterActive){
// filter your data
// your list will go into 'input' variable
// return filtered list
}
return input; //return data unfiltered;
}
});
And your html should look something like this:
<p ng-repeat="x in subcategories | my-filter:isFilterActive">
{{x.text}}
</p>
Where 'isFilterActive' variable can be placed on $scope. If 'isFilterActive' is true, your list will be filtered.
You can create a button that changes the value of it.
You can also check angular filters for more details or this tutorial: https://scotch.io/tutorials/building-custom-angularjs-filters
Have fun.

Single function from multiple ng-show functions in a controller

I have a couple of functions that I've written in Angular to display multiple ng-show attributes on a page via scopes. I attempted to put all three into a single function using if else statements, but I couldn't get the function to fire for a second time. I'm wondering if there's a way to do this in a single function, and what the best practice for this sort of functionality is.
JS Fiddle is here - http://jsfiddle.net/ezy_/01L050mr/2/
Here's the JS that's currently spread across 3 different functions.
var app = angular.module('app',[]);
function AppCtrl($scope) {
$scope.skillsState = false;
$scope.rolesState = false;
$scope.qualsState = false;
$scope.skillsStateTrigger = function() {
$scope.skillsState = true;
$scope.rolesState = false;
$scope.qualsState = false;
};
$scope.rolesStateTrigger = function() {
$scope.skillsState = false;
$scope.rolesState = true;
$scope.qualsState = false;
};
$scope.qualsStateTrigger = function() {
$scope.skillsState = false;
$scope.rolesState = false;
$scope.qualsState = true;
};
}
Do I need a $watch or $apply function to trigger updates if I set the function to fire from a single statesTrigger(resp) function?
Have a look here: updated with 1 function
$scope.triggerState = function (state) {
if (state == 'skills') {
$scope.skillsStateTrigger();
} else if (state == 'roles') {
$scope.rolesStateTrigger();
} else if (state == 'quals') {
$scope.qualsStateTrigger();
}
}
<button ng-click="triggerState('skills')">Skills</button>
<button ng-click="triggerState('roles')">Roles</button>
<button ng-click="triggerState('quals')">Quals</button>
You can even be more specific in the HTML itself like this: State variable
<body ng-app="app" class="ng-scope">
<div class="container ng-scope" ng-controller="AppCtrl">
<button ng-click="currentState = 'skills'">Skills</button>
<button ng-click="currentState = 'roles'">Roles</button>
<button ng-click="currentState = 'quals'">Quals</button>
<div class="row" ng-show="currentState == 'skills'" style="display: none;">
Skills State Active
</div>
<div class="row" ng-show="currentState == 'roles'" style="display: none;">
Roles State Active
</div>
<div class="row" ng-show="currentState == 'quals'" style="display: none;">
Quals State Active
</div>
</div>
</body>
Here is your refactor. The trick is to use an object to store the 3 states.
js:
var app = angular.module('app',[]);
function AppCtrl($scope) {
$scope.states = {
skills: false,
roles: false,
quals: false
};
$scope.trigger_state = function(state) {
for(var i in $scope.states) {
$scope.states[i] = (i == state);
}
};
}
html:
<body ng-app="app" class="ng-scope">
<div class="container ng-scope" ng-controller="AppCtrl">
<button ng-click="trigger_state('skills')">Skills</button>
<button ng-click="trigger_state('roles')">Roles</button>
<button ng-click="trigger_state('quals')">Quals</button>
<div class="row" ng-show="states.skills" style="display: none;">
Skills State Active
</div>
<div class="row" ng-show="states.roles" style="display: none;">
Roles State Active
</div>
<div class="row" ng-show="states.quals" style="display: none;">
Quals State Active
</div>
</div>
</body>
In that case it's kinda a bad idea to use 3 states, you could use 1 one variable to store "state" = "mystate" for example (since the states are exclusive).

orderBy is not updating when I click on a button

Hope somebody can help me with my problem.
I am trying to order my list on specific data and this works fine when I say upfront on what it needs to be sorted.
But when I do this when I click on a button it doesn't order my list in anyway.
Hope somebody can help me with this problem.
this is my app.js code:
app.controller("ListController", function ($scope, $interval, $http, myService, OpenDataService) {
myService.async().then(function (d) {
OpenDataService.opendata = d;
$scope.openData = OpenDataService.opendata;
$scope.order = "";
});
$scope.orderOptions = ["gemeente", "locatie"];
$scope.change = function (value) {
console.log("change");
$scope.order = value;
console.log(value);
}
$scope.test = OpenWifiData;
});
And here is the html code I use:
<li ng-click="change('gemeente')"><a>locatie</a></li>
<div id="WifiSpots" ng-controller="ListController" class="col-sm-12 col-md-4 col-md-offset-2">
<div ng-repeat="item in openData | filter:searchText | orderBy: order">
<ul class="list-group">
<li class="list-group-item">
<div class="row wifiSpots" >
<div class="col-md-2">{{item.locatie}}</div>
<div class="col-md-2">{{item.gemeente}}</div>
<div clas="col-md-1">{{item.distance}}</div>
<div clas="col-md-1">{{item.duration}}</div>
<button ng-controller="MapController" ng-click="calculateAndDisplayRoute(item.objectid)" class="btn ">Selecteer</button>
</div>
</li>
</ul>
</div>
</div>
The 'order' in the ng-repeat directive is in a different scope than the one in your controller. Add a wrapper class like so:
$scope.opts = {order: ""};
Then in your change function update that instead:
$scope.opts.order = value;
In the html:
orderBy:opts.order

Angularjs creating a div grid from a list

I am new to AngularJS and i am trying to create the following structure:
<div class="zones">
<div class="row-fluid">
<button id="btn94" class="span4 btn">All Zones</button>
<button id="btn95" class="span4 btn">Zone 1</button>
<button id="btn96" class="span4 btn">Zone 2</button>
</div>
<div class="row-fluid">
<button id="btn97" class="span4 btn">Zone 3</button>
<button id="btn98" class="span4 btn">Zone 4</button>
<button id="btn99" class="span4 btn">Zone 5</button>
</div>
<div class="row-fluid">
<button id="btn100" class="span4 btn">Zone 6</button>
</div>
</div>
In my controller I am fetching the zones via restful web service and populating a scope object, successfully.
** Controller *
ZonesFactory.query( function(data) {
// success handler
var resultType = data.resulttype;
var objects = data.result.value;
$scope.zoneList= [];
console.log(objects);
if(resultType == "list"){
angular.forEach(objects, function (item) {
$resource(item.href).get(function(rowData) {
$scope.zoneList.push(rowData.zone);
});
});
}
}, function(error) {
// error handler
});
** In HTML **
<div class="zones">
<div class="row-fluid">
<span ng-repeat="zone in zoneList">
<button id="{{$index}}" class="span4 btn">{{zone}}</button>
<span ng-if="({{$index}}%3) == 0"> </div><div class="row-fluid"> </span >
<span>
</div>
</div>
Though, i was able to break into a new div after every three items in the list.
I am faced with the following:
1. generating a simple grid structure with div and no spans
2. how to generate the ids by incrementing an ID of say btnX (where X is a number).
Please, how can i construct the grid structure using thw div and incrementing the number part of the button ID.
You can ng-repeat over an array of numbers representing your rows, and use a nested ng-repeat coupled with ng-if to display buttons with the appropriate indexes.
<div class="zones">
<div class="row-fluid" ng-repeat="row in [0,1,2]">
<button id="btn{{94+$index}}"
ng-repeat="zone in zoneList"
ng-if="($index)/3 < row + 1 && ($index)/3 >= row" class="span4 btn">
{{zone}}
</button>
</div>
</div>
The ng-if logic could be prettier, but you get the idea.
The id of each button is created with simple interpolation. I add 94 to each $index only to match the output expected in your question. You could replace 94 with a variable initialized on your scope to ensure uniqueness.
Here is a working demo: http://plnkr.co/edit/oxdD0bRq626DbzzA54c4?p=preview
I have cracked a solution that works for me, as follows:
* IN CONTROLLER **
app.filter('partition', function($cacheFactory) {
var arrayCache = $cacheFactory('partition');
var filter = function(arr, size) {
if (!arr) { return; }
var newArr = [];
for (var i=0; i<arr.length; i+=size) {
newArr.push(arr.slice(i, i+size));
}
var cachedParts;
var arrString = JSON.stringify(arr);
cachedParts = arrayCache.get(arrString+size);
if (JSON.stringify(cachedParts) === JSON.stringify(newArr)) {
return cachedParts;
}
arrayCache.put(arrString+size, newArr);
return newArr;
};
return filter;
});
* IN HTML **
<div class="zones">
<div class="row-fluid" ng-repeat="zones in zoneList | partition:3" ng-init="outerIndex = $index">
<button id="{{'btn'+(94 + outerIndex*3+ $index)}}" class="span4 btn" ng-repeat="zone in zones">{{'btn'+(94 + outerIndex*3+ $index)}} {{zone}}</button>
</div>
</div>
Thanks for the comments, especially the fiddle. Thanks.

AngularJS not filtering products list

I am having an issue with AngularJS filtering my products list. I have done a few console.log queries on my variables and all seem fine. The problem is that the view does not update to show the filtered products.
Filtering works perfectly fine when you enter the search text in the input box but it does not work when clicking on the Category menu items.
I would like to filter the product list by category when the user clicks on the menu item.
Please see my code below and any help or advice is greatly appreciated.
My app.js
myApp.controller('StoreController', function($scope, $filter, storeFactory, cartFactory) {
$scope.cartTotal = 0;
$scope.cartItems = [];
$scope.categories = [];
$scope.counted = 0;
$scope.filteredProducts = {};
//get the products
storeFactory.getProducts(function(results) {
$scope.products = results.products;
$scope.counted = $scope.products.length;
$scope.filteredProducts = results.products;
});
$scope.$watch("search", function(query){
if($scope.filteredProducts.length) {
$scope.filteredProducts = $filter("filter")($scope.products, query);
$scope.counted = $scope.filteredProducts.length;
}
});
$scope.filterProductsByCategory = function(categoryName){
console.log('category filter');
/*$scope.products.forEach(function(o,i){
console.log('filter');
if( o.category_id !== categoryId ){
$scope.filteredProducts.splice(i,1);
console.log('removing');
console.log(o);
}
});*/
$scope.filteredProducts = $filter("filter")($scope.filteredProducts, categoryName);
console.info('the filtered items');
console.log($scope.filteredProducts);
$scope.counted = $scope.filteredProducts.length;
}
$scope.getCategories = function(){
storeFactory.getCategories(function(results){
$scope.categories = results.rows;
});
}
$scope.getCategories();
});
My store.htm
UPDATE :
I removed the extra controller reference and wrapped everything in one div.
<div ng-controller="StoreController">
<!-- the sidebar product menu -->
<div class="block-content collapse in">
<div class="daily" ng-repeat="category in categories | orderBy:'name'">
<div class="accordion-group">
<div ng-click="filterProductsByCategory(category.category_name)" class="accordion-toggle collapsed">{{category.category_name}}</div>
</div>
</div>
</div>
</div>
<!-- Load store items start -->
<div class="label">Showing {{counted}} Product(s)</div>
<div class="row" ng-repeat="product in filteredProducts | orderBy:'product_name'" style="margin-left: 0px; width: 550px;">
<hr></hr>
<div class="span1" style="width: 120px;">
<!-- <a data-toggle="lightbox" href="#carouselLightBox"> -->
<a data-toggle="lightbox" href="#carouselLightBox{{product.product_id}}">
<!--img alt={{ product.product_name }} ng-src="{{product.image}}" src="{{product.image}}" /-->
<img id="tmp" class="" src="images/products/{{product.product_image_filename}}" alt=""></img>
</a>
<div class="lightbox hide fade" id="carouselLightBox{{product.product_id}}" style="display: none;">
<div class='lightbox-content'>
<img src="images/products/{{product.product_image_filename}}" alt="" />
<!--img alt={{ product.product_name }} ng-src="{{product.image}}" src="{{product.image}}" /-->
<button class="btn btn-primary" id="close_lightbox" ng-click="closeBox(product.product_id, $event)">Close</button>
</div>
<style>
#close_lightbox
{
position: absolute;
top: 5px;
right: 5px;
}
</style>
</div>
</div>
<div class="span6" style="width: 330px; margin-bottom: 15px;">
<h5 style="font-size: 14px; font-weight: bold;">{{product.product_name}}</h5>
<p>{{product.product_description }}</p>
<p>Category : {{product.category_name}}</p>
</div>
<div class="span3">
<p class="price">Price : <strong>R{{ product.product_price }}</strong></p>
</div>
</div>
<!-- end of controller -->
</div>
$scope.filteredProducts = {};
//get the products
storeFactory.getProducts(function (results) {
$scope.products = results.products;
$scope.counted = $scope.products.length;
$scope.filteredProducts = results.products;
});
Is results.products an array of objects or an object of objects? Because $filter('filter')($scope.products,query); expects $scope.products to be an array.
$scope.$watch("search", function (query) {
if($scope.filteredProducts.length) {
$scope.filteredProducts = $filter("filter")($scope.products, query);
$scope.counted = $scope.filteredProducts.length;
}
});
Here's what I'm thinking this should look like and you won't need the $watch statement or the filteredProducts array/object, In controller:
$scope.search = '';
$scope.products = [];
$scope.categories = ['category1','category2','category3'];
// assuming that your store function getProducts returns a promise here
storeFactory.getProducts().then(function(results){
$scope.products = results.products; // needs to be an array of product objects
});
$scope.filterProductsByCategory = function(category){
$scope.search = category;
};
Then in your HTML Partial, this is not exactly how your's is, I'm just showing you here in shorter form what is possible:
<button ng-repeat="cat in categories" ng-click="filterProductsByCategory(cat)">{{cat}}</button>
<div class="row" ng-repeat="product in products | filter:search | orderBy:'product_name'">
<!-- Product Information Here -->
</div>
I created a JSFiddle to demonstrate: http://jsfiddle.net/mikeeconroy/QL28C/1/
You can free form search with any term or click a button for a category.
The side bar is using one instance of StoreController, and the main div is using another instance of StoreController. Each instance having its own scope. The should both use the same controller instance: wrap everything inside a div, and use a unique StoreController for this wrapping div.

Categories