Angular JS : Unordered List Elements not getting displayed - javascript

I trying to create a unordered list using controller and view page. Please find the controller below:
(function() {
'use strict';
angular
.module('app.sdb')
.controller('SdbController', SdbController)
SdbController.$inject = ['logger'];
/* #ngInject */
function SdbController(logger) {
var vm = this;
vm.models = {
selected: null,
lists: {"A": [], "B": []}
};
for(var i=1;i<=3;i++) {
vm.models.lists.A.push({label: "Item A" + i});
vm.models.lists.B.push({label: "Item B" + i});
}
activate();
function activate() {
vm.title = 'Safe Digital Board';
logger.info('Activation', 'Sdb Controller', 'Template Rendered');
}
}
})();
Please find the mark up below:
<div>
<ul>
<li ng-repeat="item in vm.models"> Hello {{item.label}} </li>
</ul>
</div>
But am getting only the below O/P:
Hello
Hello
Seeking help... Please advise

Problem is with your model object. Your ng-repeat should be ng-repeat="item in vm.models.lists.A"
Please find a working plunker
<div>
<ul>
<li ng-repeat="item in vm.models.lists.A"> Hello {{item.label}} </li>
</ul>
</div>
To show both lists you need to write your template as shown below:
<div>
<ul ng-repeat="items in vm.models.lists">
<li ng-repeat="item in items"> Hello {{item.label}} </li>
</ul>
</div>

try using $scope and create an array for $scope.vm.models, like:
.controller('SdbController', ['$scope', $log,
function($scope, $log) {
$scope.reset = function() {
$scope.vm = {};
$scope.vm.models = [{label:"element01"},
};
$scope.reset();
}
}]);

Related

How to create a property inside ng-repeat scope

I'm trying to make an editable list of items. There is an editing mode of each item.
HTML:
<ul ng-controller="ItemCtrl">
<li ng-repeat="item in items">
<div class="edit-off" ng-hide="editMode">...</div>
<div class="edit-on" ng-show="editMode">...</div>
<button ng-click="toggleEdit()">Edit</button>
</li>
</ul>
JavaScript:
angular.module("app", [])
.controller("ItemCtrl", function($scope) {
$scope.items = [...]; // list of items
$scope.editMode = false;
$scope.toggleEdit = function() {
$scope.editMode = !$scope.editMode;
};
});
I know that this code isn't correct since I attached editMode to the controller scope, not to ngRepeat scope. With this code, whenever I click at any button, all items will turn into editing mode.
All I want is that every item has its own editMode property in its scope, so that I can edit them individually.
put your property on each item:
<ul ng-controller="ItemCtrl">
<li ng-repeat="item in items">
<div class="edit-off" ng-hide="item.editMode">...</div>
<div class="edit-on" ng-show="item.editMode">...</div>
<button ng-click="toggleEdit(item)">Edit</button>
</li>
</ul>
angular.module("app", [])
.controller("ItemCtrl", function($scope) {
$scope.items = [...]; // list of items
$scope.toggleEdit = function(item) {
item.editMode = !item.editMode;
};
});
You can use $index like this:
angular.module("app", [])
.controller("ItemCtrl", function($scope) {
$scope.items = [...]; // list of items
$scope.editMode = [];
$scope.toggleEdit = function(index) {
$scope.editMode[index] = !$scope.editMode[index];
};
});
HTML:
<ul ng-controller="ItemCtrl">
<li ng-repeat="item in items">
<div class="edit-off" ng-hide="editMode[$index]">...</div>
<div class="edit-on" ng-show="editMode[$index]">...</div>
<button ng-click="toggleEdit($index)">Edit</button>
</li>
</ul>
Demo: https://jsfiddle.net/iRbouh/rftfx7j4/
You can add the property in each item and use it to edit.
$scope.items = [{name: 'misko', gender: 'male'},{name: 'misko1', gender: 'male'}];
angular.forEach($scope.items, function(obj) {
obj["editMode"] = false
});
in view
<ul ng-controller="ItemCtrl">
<li ng-repeat="item in items">
<div class="edit-off" ng-hide="editMode[$index]">...</div>
<div class="edit-on" ng-show="editMode[$index]">...</div>
<button ng-click="item.editMode = !item.editMode">Edit</button>
</li>
</ul>
Use $index.
HTML:
<ul ng-controller="ItemCtrl">
<li ng-repeat="item in items track by $index">
<div class="edit-off" ng-hide="editMode">...</div>
<div class="edit-on" ng-show="editMode">...</div>
<button ng-click="toggleEdit($index)">Edit</button>
</li>
</ul>
JS:
angular.module("app", [])
.controller("ItemCtrl", function($scope) {
$scope.items = [...]; // list of items
$scope.toggleEdit = function($index) {
setEditMode($scope.items[$index]);
};
});
function setEditMode(item) {
item.editMode = false;
}
Add the editMode attribute to each item, as said in #John's answer.
Here's the working Plunker:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.items = [
{ id:2, ds: 'test1' },
{ id:2, ds: 'test2' },
{ id:2, ds: 'test3'}]; // list of items
$scope.toggleEdit = function($index) {
$scope.items[$index].editMode = !$scope.items[$index].editMode;
};
});
There are a lots way can implement this, see example:
<ul ng-controller="ItemCtrl">
<li ng-repeat="item in items">
<div class="edit-off" ng-hide="editMode[$index]">{{editMode[$index]}}</div>
<div class="edit-on" ng-show="editMode[$index]">{{editMode[$index]}}</div>
<button ng-click="toggleEdit($index)">Edit</button>
</li>
var myApp = angular.module("myApp", [])
.controller("ItemCtrl", function($scope) {
$scope.items = ["aaa","bbb","ccc"]; // list of items
$scope.editMode = [true,true,true];
$scope.toggleEdit = function(index) {
$scope.editMode[index] = !$scope.editMode[index];
};
});
http://jsfiddle.net/Lvc0u55v/7052/

how to create Custom filter angularjs javascript controller side?

how to create Custom filter angularjs javascript controller side?
i would like to search in array called segments by SegmentId, to create filter that do foreach on segments array search by SegmentId -
//Controller
$scope.GetSegmentDetails = function (id) {
$scope.SegmentName = $filter('SegmentById')($scope.segments,id);
}
//Filter
app.filter('SegmentById', function () {
return function (input, searchPerson) {
if (!searchPerson)
return input;
var results = [];
angular.forEach(input, function (person) {
}
});
return results;
}
});
You dont have to write your one filter to filter by SegmentId. Here you have an example
function MyCtrl($scope, $filter) {
$scope.data = [{"SegmentId":"1","Description":"hod Registrations"}, {"SegmentId":"2","Description":"hod Inactive"}, {"SegmentId":"3","Description":"hod testUpd"}, {"SegmentId":"8","Description":"hod test"}, {"SegmentId":"1111","Description":"hod Release"}, {"SegmentId":"12","Description":"hod Requests"}, {"SegmentId":"13","Description":"hod Welcome Back"}]
$scope.filterData = function(segmentId) {
return $filter('filter')($scope.data, { SegmentId: segmentId });
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="MyCtrl">
Full:
<ul>
<li ng-repeat="Segment in data">
{{Segment.SegmentId}}
</li>
</ul>
Filtered in View:
<ul>
<li ng-repeat="Segment in data | filter:{SegmentId:1111}">
{{Segment.SegmentId}}
</li>
</ul>
Filtered in Controller:
<ul>
<li ng-repeat="Segment in filterData(1111)">
{{Segment.SegmentId}}
</li>
</ul>
</div>
Only need to add in your controller the filter dependency and then call it.
app.controller("YourController", ['$scope', '$filter', function ($scope, $filter){
$filter('filterName')($args));
}]);

How can I make this angular controller re-usable thoughout the site?

I have this tab functionality made in AngularJS and I want it to be re-usable throughout my website without having to repeat the logic. Is there a way I can make it a directive? or maybe a service?
Here is the html:
<ul class="expandingTab">
<li ng-class="{active: isSet(1)}"><span>MY GMM</span></li>
<li ng-class="{active: isSet(2)}"><span>ALL TRANSACTIONS</span></li>
</ul>
<div ng-show="isSet(1)">
<h1>Tab 1</h1>
</div>
<div ng-show="isSet(2)">
<h1>Tab 2</h1>
</div>
Here is the JS:
var myApp = angular.module('myApp', []);
myApp.controller('TabController', ['$scope', function($scope) {
$scope.tab = 1;
$scope.setTab = function(tab) {
$scope.tab = tab;
};
$scope.isSet = function(checkTab) {
return $scope.tab === checkTab;
};
}]);
EDIT
I really would like to just have the functionality in a service and be able to inject it as a dependency to controllers that will use it. This way I can keep all the content in the view where I want it. I feel like my logic is close, but I still can't get it working. Can anyone tell me what I am doing wrong?
HTML
<ul class="expandingTab">
<li ng-class="{active: tabs.toggleTabs.isSet(1)}"> <span>Tab 1</span></li>
<li ng-class="{active: tabs.toggleTabs.isSet(2)}"><span>Tab 2</span></li>
</ul>
<div ng-show="tabs.toggleTabs.isSet(1)">
<h1>Tab 1</h1>
</div>
<div ng-show="tabs.toggleTabs.isSet(2)">
<h1>Tab 2</h1>
</div>
Controller
var app = angular.module('myApp', ['services']);
app.controller('TabController', ['$scope', 'toggleTabs',function($scope, toggleTabs) {
}]);
Service
var tabsApp = angular.module('services', []);
tabsApp.service('toggleTabs', function() {
this.tab = 1;
this.setTab = function(tabSelected) {
this.tab = tabSelected;
}
this.isSet = function(checkTab) {
return this.tab === checkTab;
}
});
And here is a Plunker with all this code: http://plnkr.co/edit/liT7BIGlIRg9boH81NaY?p=preview
In response to your comments, here is an example that shows how you can inject content into the directive to make it more reusable. It doesn't use tabs, but it illustrates the concept. JsBin example.
HTML
<body ng-controller="testController">
<header bf-nav navs="navs"></header>
</body>
JavaScript
(function() {
'use strict';
var app = angular.module('test', []);
app.directive('bfNav', navDirective);
function navDirective() {
return {
restrict: 'AE',
scope: {
navs: '='
},
template: '<nav class="navbar navbar-default" role="navigation"><div class="container-fluid"><ul class="nav navbar-nav"><li ng-repeat="nav in navs" ng-click="setNav(nav.index)" ng-class="{ active: isActive(nav.index) }">{{nav.title}}</li></ul></div></nav>',
controller: navController
};
}
function navController($scope) {
$scope.activeNav = 1;
$scope.isActive = function (index) {
return $scope.activeNav === index;
};
$scope.setNav = function (index) {
$scope.activeNav = index;
};
}
app.controller('testController', ['$scope', testController]);
function testController($scope) {
$scope.navs = [
{ index: 1, title: 'Nav 1' },
{ index: 2, title: 'Nav 2' }
];
}
})();
Your directive is not working because you have not specified a 'template' for it (your html) in conjunction with using an isolate scope (scope: {}). Basically the directive cannot talk to the html that you have put the tabs on. (among other things)
Try:
ocApp.directive('tabs', function(){
return{
restrict: 'A',
scope: {},
templateUrl: 'tabs.html', //Put your html into a seperate file and add the path here
controller: function($scope){
$scope.tab = 1;
$scope.setTab = function(tab){
$scope.tab = tab;
};
$scope.isSet = function(checkTab){
return $scope.tab === checkTab;
};
}
};
});
For tabs.html
<ul class="expandingTab">
<li ng-class="{active: isSet(1)}"><span>MY GMM</span></li>
<li ng-class="{active: isSet(2)}"><span>ALL TRANSACTIONS</span></li>
</ul>
<div ng-show="isSet(1)">
<h1>Tab 1</h1>
</div>
<div ng-show="isSet(2)">
<h1>Tab 2</h1>
</div>
And for index.html you would use
<div tabs></div>
or
<tabs></tabs>
I'd recommend this reference for directives (there are many other resources on the googles and on SO)
I ended up doing this as a service and it seems to be just what I wanted. I can keep the html in the view and just inject the service into whatever controller I want to use tabs on here is the code:
HTML
<ul class="expandingTab">
<li ng-class="{active: .toggleTabs.isSet(1)}"><span>Tab 1</span></li>
<li ng-class="{active: toggleTabs.isSet(2)}"><span>Tab 2</span></li>
</ul>
<div ng-show="toggleTabs.isSet(1)">
<h1>Tab 1</h1>
</div>
<div ng-show="toggleTabs.isSet(2)">
<h1>Tab 2</h1>
</div>
Controller
var app = angular.module('myApp', ['services']);
app.controller('TabController', ['$scope', 'toggleTabs',function($scope, toggleTabs) {
$scope.toggleTabs = toggleTabs;
}]);
Service
var tabsApp = angular.module('services', []);
tabsApp.service('toggleTabs', function() {
this.tab = 1;
this.setTab = function(tabSelected) {
this.tab = tabSelected;
}
this.isSet = function(checkTab) {
return this.tab === checkTab;
}
});

angular.js template variables to bootbox dialog?

I've been trying to figure this out for like 10 hours now. Time to ask for help!
I'm trying to pass a variable from an angular.js template variable to bootbox for a nice looking confirmation prompt.
Assume that I have the following (abbreviated for clarity):
<script>
$(document).on("click", ".confirm", (function(e) {
e.preventDefault();
bootbox.confirm("This needs to be the value of {{item.name}}", function(confirmed) {
console.log("Confirmed: "+confirmed);
});
}));
</script>
which is executed as such:
<ul class="list-group">
<li ng-repeat="item in items">
<span class="glyphicon glyphicon-fire red"></span>
</li>
</ul>
When the user clicks the link, I would like a the confirmation box to appear, and I need to include attributes like {{item.name}} and {{item.row}} that are specific to this element in the list.
I have read up on the $compile functionality of angular.js and I got it working in so far as having a <div compile="name"> but that doesn't help me for retrieving a single entry out of my list as I am iterating. Any help would be appreciated!
Applied as a directive...
HTML:
<body ng-app="myApp" ng-controller="MainController">
<ul class="list-group">
<li ng-repeat="item in items">
<confirm-button name="{{item.name}}"></confirm-button>
</li>
</ul>
</body>
JS:
angular.module('myApp', [])
.controller('MainController', function($scope) {
$scope.items = [
{ name: 'one' },
{ name: 'two' },
{ name: 'three' }
];
})
.directive('confirmButton', function(){
return {
restrict: 'E',
scope: { name: '#' },
template: '<span class="glyphicon glyphicon-fire red" ng-click="confirm(name)">Button</span>',
controller: function($scope) {
$scope.confirm = function(name) {
bootbox.confirm("The name from $scope.items for this item is: " + name, function(result){
if (result) {
console.log('Confirmed!');
} else {
console.log('Cancelled');
}
});
};
}
}
});
Working plunk
This is a simple approach, but depending on what you're trying to do it may not suit you:
var app = angular.module('app', []);
app.controller('AppCtrl', function ($scope) {
$scope.items = [
{ name: "Bla bla bla bla?", url: "http://stackoverflow.com" },
{ name: "Ble ble ble ble?", url: "http://github.com" }
];
$scope.confirm = function (item) {
bootbox.confirm("Confirm?", function (confirmed) {
alert('Confirmed: '+ confirmed +'. Url: '+ item.url);
});
};
});
In your html:
<div ng-app='app' ng-controller="AppCtrl">
<ul class="list-group">
<li ng-repeat="item in items">
<a ng-click="confirm(item)">
<span class="glyphicon glyphicon-fire red"></span>
{{ item.name }}
</a>
</li>
</ul>
</div>
Depending on what you want, maybe you should check out the directives: https://docs.angularjs.org/guide/directive

AngularJS multiple uses of Controller and rootScope

I want to use a controller on 2 seperated HTML elements, and use the $rootScope to keep the 2 lists in sync when one is edited:
HTML
<ul class="nav" ng-controller="Menu">
<li ng-repeat="item in menu">
{{item.title}}
</li>
</ul>
<div ng-controller="Menu">
<input type="text" id="newItem" value="" />
<input type="submit" ng-click="addItem()" />
<ul class="nav" ng-controller="Menu">
<li ng-repeat="item in menu">
{{item.title}}
</li>
</ul>
</div>
JS
angular.module('menuApp', ['menuServices']).
run(function($rootScope){
$rootScope.menu = [];
});
angular.module('menuServices', ['ngResource']).
factory('MenuData', function ($resource) {
return $resource(
'/tool/menu.cfc',
{
returnFormat: 'json'
},
{
getMenu: {
method: 'GET',
params: {method: 'getMenu'}
},
addItem: {
method: 'GET',
params: {method: 'addItem'}
}
}
);
});
function Menu($scope, MenuData) {
// attempt to add new item
$scope.addNewItem = function(){
var thisItem = $('#newItem').val();
MenuData.addItem({item: thisItem},function(data){
$scope.updateMenu();
});
}
$scope.updateMenu = function() {
MenuData.getMenu({},function(data){
$scope.menu = data.MENU;
});
}
// get menu data
$scope.updateMenu();
}
When the page loads, both the UL and the DIV display the correct contents from the database, but when i use the addNewItem() method only the DIV gets updated.
Is there a better way to structure my logic, or can I do something to make sure the $scope.menu in the UL gets updated at the same time?
Here's an example of something similar: http://plnkr.co/edit/2a55gq
I would suggest to use a service that holds the menu and its methods. The service will update the menu which is referenced by the controller(s).
See a working plunker here: http://plnkr.co/edit/Bzjruq
This is the sample JavaScript code:
angular
.module( 'sampleApp', [] )
.service( 'MenuService', [ '$rootScope', function( $rootScope ) {
return {
menu: [ 'item 1' ],
add: function( item ) {
this.menu.push( item );
}
};
}])
.controller( 'ControllerA', [ 'MenuService', '$scope', function( MenuService, $scope ) {
$scope.menu = MenuService.menu;
$scope.addItem = function() {
MenuService.add( $scope.newItem );
};
}]);
And the sample Html page:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="sampleApp">
<div ng-controller="ControllerA">
<ul>
<li ng-repeat="item in menu">{{item}}</li>
</ul>
<input type="text" ng-model="newItem" /><input type="submit" ng-click="addItem()" />
</div>
<div ng-controller="ControllerA">
<ul>
<li ng-repeat="item in menu">{{item}}</li>
</ul>
</div>
</body>
</html>
Edit:
Here is the updated version plunker. it works in two controller.
Main idea is using service and broadcast to sync the data with the directive.
app.service('syncSRV', function ($rootScope) {
"use strict";
this.sync = function (data) {
this.syncData = data;
$rootScope.$broadcast('updated');
};
});
app.controller('MainCtrl1', ['$scope', function ($scope) {
}])
.controller('MainCtrl2', ['$scope', function ($scope) {
}]);
app.directive('sync',function (syncSRV) {
"use strict";
return {
template: '<div><input ng-model="syncdata" type="text" /></div> ',
controller: function ($scope, $element, $attrs) {
$scope.$watch('syncdata', function (newVal, oldVal, $scope) {
syncSRV.sync(newVal);
}, true);
}
};
}).directive('dataview', function (syncSRV) {
"use strict";
return {
template: '<div>Sync data : {{data}}</div> ',
controller: function ($scope, $element, $attrs) {
$scope.$on('updated', function () {
$scope.data = syncSRV.syncData;
});
}
};
});
<div ng-controller="MainCtrl1">
<fieldset>
<legend> Controller 1</legend>
<div dataview></div>
<div sync></div>
</fieldset>
</div>
<div ng-controller="MainCtrl2">
<fieldset>
<legend> Controller 2</legend>
<div dataview></div>
<div sync></div>
</fieldset>
</div>
Here is what I would do for this case.
I will create a directive for
<ul class="nav" ng-controller="Menu">
<li ng-repeat="item in menu">
{{item.title}}
</li>
</ul>
so once item is updated, it will be updated in both directive.
small example
I just want to update and simplify the selected answer. It seems you can reduce this by deleting this line:
$rootScope.$broadcast( 'MenuService.update', this.menu );
and this chunk:
$scope.$on( 'MenuService.update', function( event, menu ) {
$scope.menu = menu;
});
The reason being, we are already using a Service, and that basically binds the two identical controllers, so no need to use $rootScope.$broadcast and add an observable.
Working plunk here:
http://plnkr.co/edit/1efEwU?p=preview
You only need to link the service, when I refactor the code I was able to reduce it to 13 lines instead of 22.

Categories

Resources