angular.js template variables to bootbox dialog? - javascript

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

Related

Angular JS : Unordered List Elements not getting displayed

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();
}
}]);

Sharing data from API between controllers in AngularJS

I have a parent controller with some children controllers, and I want them all to share the same data that I retrieve from an Api service.
Controllers:
var app = angular.module('mymodule',[]);
app.controller('main', ['$scope', 'Api', function($scope, Api) {
var getList1 = Api.getList1()
.then(function(resp) {
$scope.list1 = resp.data;
});
var getList2 = Api.getList2()
.then(function(resp) {
$scope.list2 = resp.data;
});
}]);
app.controller('child1', ['$scope', function($scope) {
$scope.list1 = ?
$scope.list2 = ?
}]);
app.controller('child2', ['$scope', function($scope) {
$scope.list1 = ?
}]);
View:
<div ng-controller="main">
<ul>
<li ng-repeat="list in list1">
{{list.item}}
</li>
</ul>
<div ng-controller="child1">
<ul>
<li ng-repeat="list in list1">
{{list.item}}
</li>
</ul>
<ul>
<li ng-repeat="list in list2">
{{list.item}}
</li>
</ul>
</div>
<div ng-controller="child1">
<ul>
<li ng-repeat="list in list1">
{{list.item}}
</li>
</ul>
</div>
</div>
I tried to use this solution with Angular’s events mechanism ($on, $emit).
The problem was that I had to figure out which child controller is active and send the data when the promise has resolved. It ends with ugly spaghetti code...
Well, the best way is to use a service to have your API handling atomar placed inside your application. This fiddle shows you how you could achieve what you try to. By using AngularJS services you will be able to share the same data, objects and functions between controllers and let them interact with eachother. This is undepending on the amount of your controllers inside your application.
The following example is a full working API service with real HTTP-Requests and a real AngularJS service handling. It will help you by implement such logic inside your application. Please dont forget to check out the fiddle demo.
View
<div ng-controller="MyCtrl">
<h1>
MyCtrl
</h1>
<button ng-click="clearData()">
Clear data by using MyCtrl
</button>
<div ng-repeat="user in users">
<p>
Username: {{ user.name }}
</p>
</div>
</div>
<br /><br />
<div ng-controller="MyOtherCtrl">
<h1>
MyOtherController
</h1>
<button ng-click="clearData()">
Clear data by using MyOtherController
</button>
<div ng-repeat="user in users">
<p>
Username: {{ user.name }}
</p>
</div>
</div>
AngularJS Application
var myApp = angular.module('myApp',[]);;
myApp.controller('MyCtrl', function ($scope, apiService) {
$scope.users = apiService.getResponseData();
$scope.$watch(function () { return apiService.getResponseData()}, function (newValue, oldValue) {
$scope.users = newValue
});
$scope.clearData = function () {
apiService.reset();
}
});
myApp.controller('MyOtherCtrl', function ($scope, apiService) {
apiService.loadData();
$scope.$watch(function () { return apiService.getResponseData()}, function (newValue, oldValue) {
$scope.users = newValue
});
$scope.clearData = function () {
apiService.reset();
}
})
myApp.service('apiService', function ($http) {
var responseData = null;
return {
loadData: function () {
return $http({
url: 'https://jsonplaceholder.typicode.com/users',
method: 'GET'
}).then(function (response) {
responseData = response.data
});
},
getResponseData: function () {
return responseData
},
reset: function () {
responseData = null;
}
}
});
As your data is in the scope of the parent controller, you can access it in children controllers with $scope.$parent:
app.controller('child1', ['$scope', function($scope) {
$scope.list1 = $scope.$parent.list1;
$scope.list2 = $scope.$parent.list2;
}]);
Write your children as directives, and then you can inject data on the scope.
yourModule.directive('child1', function() {
return {
scope: {list1:'=',
controller: function (scope) {
//not sure you even need a controller, but it might look like this
scope.doSomething = function() {
//access scope.list1 here
}
},
template: '<ul><li ng-repeat="list in list1">{{list.item}}<li><ul>'
}
}
Usage:
<child1 list1="list1"></child1>

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;
}
});

AngularJS dynamically populate details from json based on item selected

I am trying to create a page where you have few items in a list group which when selected should show more details.
Please view the example here http://plnkr.co/edit/Oava3pA9OTsm80K58GdT?p=preview
How can I populate the details from the json file based on the item that is selected in the list group?
This is what I have so far.
html:
<div ng-controller=ItemsController>
<h3>Test</h3>
<div class="row">
<div class="col-md-4">
<div class="panel panel-default">
<ul class="list-group">
<a class="list-group-item" ng-repeat="item in itemDetails">{{item.name}}</a>
</ul>
</div>
</div>
<div class="col-md-8">
<div class="panel panel-default">
<h2>Name: </h2>
<br />Address Line 1:
<br />Address Line 2:
<br />Suburb:
<br />Phone:
<br />Email:
</div>
</div>
</div>
</div>
script:
var myItemsApp = angular.module('myItemsApp', []);
myItemsApp.factory('itemsFactory', ['$http', function($http){
var itemsFactory ={
itemDetails: function() {
return $http(
{
url: "mockItems.json",
method: "GET",
})
.then(function (response) {
return response.data;
});
}
};
return itemsFactory;
}]);
myItemsApp.controller('ItemsController', ['$scope', 'itemsFactory', function($scope, itemsFactory){
var promise = itemsFactory.itemDetails();
promise.then(function (data) {
$scope.itemDetails = data;
console.log(data);
});
}]);
json:
[
{
"$id":"1",
"name":"Test itemName 1",
"themeName":"ASD",
"addressLine1":"18 Banksia Street",
"addressLine2":null,
"suburb":"Heidelberg",
"state":"VIC",
"postalCode":"3084",
"contactPhone":"+61 3 123456",
"emailAddress":"qwerty.it#xyz.com"
},
{
"$id":"2",
"name":"Test itemName 2",
"themeName":"WER",
"addressLine1":"11 Riverview Place",
"addressLine2":"Metroplex on Gateway",
"suburb":"Murarrie",
"state":"QLD",
"postalCode":"4172",
"contactPhone":"1300 73123456",
"emailAddress":"asdfg.it#xyz.com"
},
{
"$id":"3",
"name":"Test itemName 3",
"themeName":"ERT",
"addressLine1":"60 Waterloo Road",
"addressLine2":null,
"suburb":"North Ryde",
"state":"NSW",
"postalCode":"2113",
"contactPhone":"123456",
"emailAddress":"zxcvb.it#xyz.com"
}
]
Any help would be greatly appreciated.
I am very new to programming. Please also feel free to alternative ways of achieving this if I have done it wrong.
You can use the ng-click directive to specify what happens when you click something.
So I made it assign the clicked item to the $scope.selected object using a function ($scope.select(item)) and then I bound the properties of that object to your little details section. That's probably the simplest way to do it.
Ctrl
$scope.select = function(item) {
$scope.selected = item;
}
$scope.selected = {};
HTML
<a class="list-group-item" ng-click="select(item)" ng-repeat="item in itemDetails">
{{item.name}}
</a>
And the selected object is then available like this:
<h2>Name: {{selected.name}}</h2>
etc...
See my example here: http://plnkr.co/edit/mUMZ0VGO8l1ufV1JJNQE?p=preview

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