I'd like to pass a function with to BootstrapUI's popover directive. The attribute is normally a string, but I need to do an AJAX call to supply the attribute to the directive. Currently, the popover displays the function as a string e.g. "showItem(one)" rather than the result of calling the function, e.g. "Item is one". Thanks!
The HTML
<li ng-repeat="item in items"
popover-placement="top"
popover-trigger="mouseenter"
uib-popover="showItem({{item.id}})">
{{item.id}}
</li>
The JS
app.controller("uibController", ["$scope", function ($scope) {
$scope.items = [
{id: "one"},
{id: "two"},
{id: "three"}
];
$scope.showItem = function(item){
$http.get('url').success(function(response){
//data for popover directive
return "Item is " + item.id;
})
};
}]);
Codepen
http://codepen.io/anon/pen/PZQOdY
<div ng-repeat="item in items"
popover-placement="bottom"
popover-trigger="mouseenter"
uib-popover="{{showItem(item)}}">
{{item.id}}
</div>
Related
Scenario:
I have a list of items rendered within an ng-repeat.
Each item has an item template.
When one of the items is clicked, that item becomes "active". That item then has a different template from the other items in the list.
By default, the first item in the list is "active".
Is it possible to use ui-router to accomplish this? I know I can use a templateURL function to get the state parameters, but then it would be applied to all items.
If possible, I'd like to avoid using ng-if/ng-switch since the active item would also have several possible nested states with different templates.
angular.module("app", ["ui.router"]);
angular.module("app")
.config(function($stateProvider) {
$stateProvider
.state("list", {
url: "/list",
abstract: true,
templateUrl: "list.html"
controller: "ListCtrl",
controllerAs: "listC",
})
// how to configure this to change template for "active" item in the list?
.state("list.item", {
url: "/list/item/:itemId"
});
});
angular.module("app")
.controller("ListCtrl", function($state) {
// this would be retrieved asynchronously
this.items = [
{id: 1, name: "One"},
{id: 2, name: "Two"},
{id: 3, name: "Three"},
];
$state.go("list.item", {itemId: this.items[0].id})
});
<div ng-app="app" ui-view></div>
<script type="text/ng-template" id="list.html">
<ul>
<li ng-repeat="item in listC.items" ui-view></li>
</ul>
</script>
<script type="text/ng-template" id="list-item.html">
<a ui-sref="list.item({itemId: item.id})">{{ item.name }}</a>
</script>
<script type="text/ng-template" id="list-item-active.html">
<h3>{{ item.name }}<h3>
</script>
take a look at http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.directive:ui-sref-active
you should do something like:
<a ui-sref="list.item({itemId: item.id})" ui-serf-active="active">{{ item.name }}</a>
I've similarly asked this before, but neither solution proved useful.
I currently have a store app built with AngularJS, my problem is, I need to be able to click on one item and open into the "item" view and display only the information with a matching ID from the items array stored in a services.
For example. Item one displayed on store view has an id of 1, and on the store displays the product name etc. When clicked, the item is opened with the item view to display just that product and it's information.
Here's my store Controller:
'use strict';
angular.module('angularStoreApp')
.controller('storeCtrl', function($scope, StoreService){
$scope.items = StoreService.items();
});
Services (Shortened to save spare, there's 12 other items).
'use strict';
angular.module('angularStoreApp')
.service("StoreService", function() {
var items = [ {
itemId: 1,
qty: 0,
stock: 5,
price: 99.00,
name: 'Almond Toe Court Shoes, Patent Black',
category: 'Womens Footerwear'
},
{
qty: 0,
stock: 4,
price: 42.00,
name: 'Suede Shoes, Blue',
category: 'Womens Footerwear'
}];
this.items = function() {
return items;
};
});
Store View
<!-- Start of item iteration -->
<div ng-repeat="item in items">
<!-- Start of item -->
<div class="item">
<div class="item_info">
<img src="http://i.imgur.com/Bn1iB6X.jpg"/>
<div class="item_footer">
<div class="info_text">
<h2>{{item.name| limitTo: 8}}...</h2>
<span>{{item.price | currency}}</span>
</div>
<div class="icon">
<a ng-href="#"><button role="button">More</button></a>
</div>
</div>
</div>
</div>
<!-- End of item -->
</div>
<!-- End of item iteration-->
Item Ctrl
'use strict';
angular.module('angularStoreApp')
.controller('itemCtrl', function ($scope, StoreService) {
$scope.items = StoreService.items();
});
Item View
<div ng-include="'components/navbar/navbar.html'"></div>
<div ng-repreat="item in items">
<div class="item-page-container">
<div class="item-p-img">
{{item.name}}
</div>
<div class="item-p-tab-Container">
<ul>
<li>{{item.name}}</li>
<li></li>
<li></li>
</ul>
</div>
</div>
</div>
Please ask for any more code or for easier view, see my Github Repo
Please be clear on the function, feel free to put into a plunker, my Javascript skills come from Angular, but searching an array like this I haven't done before. I'd need a good solution where I can transfer/learn the logic.
Store View
(not sure about your routing) but would try smt like this:
<a ng-href="/items/{{item.itemID}}"><button role="button">More</button></a>
this should send you to your item view.
In your Item ctrl, if you inject $routeParams you could fetch the id like so:
item_id = $routeParams.id
and then search for your item like so:
items = StoreService.items();
$scope.item = items.indexOf(item_id)
so in your item view remove the ng-repeat and work with the item object.
As I said before, not enterily sure of your project's structures,. but this should get you on your way.
Make your routes like this :
$routeProvider
.when('/items', {
templateUrl: 'yourtemplate-path/items.html',
controller: 'yourItemController'
})
.when('/items/:itemId', {
templateUrl: 'yourtemplate-path/items-detail.html',
controller: 'yourItemDetailsController'
})
Your controller:
For items,
'use strict';
angular.module('angularStoreApp')
.controller('storeCtrl', function($scope, StoreService){
StoreService.items(function(){
$scope.items = data;
});
});
For item detail page,
'use strict';
angular.module('angularStoreApp')
.controller('storeDetailsCtrl', function($scope, $routeParams, StoreService){
StoreService.items({itemId: $routeParams.itemId}, function(){
$scope.item = data;
});
});
and create your new service, which fetches the data based on this id(itemId)
NOTE: I didn't tested the code.
In one of my Angular.JS controllers, I have the following:
app.controller("MyController", ["$scope", function($scope){
$scope.messages = [
new Message(1),
new Message(2)
];
$scope.addMessage = function(x) { $scope.messages.push(new Message(x)); }
}]);
Then in my main HTML page, I have
<message message="message" ng-repeat="message in messages">
This is bound to a directive:
app.directive("message", function() {
return {
restrict: "E",
scope: {
message: "="
},
templateUrl: "js/Directives/message.html"
};
});
The template file is:
<li class="message">{{message.msg}} </li>
However, when I call addMessage on the controller, while it does add to $scope.messsages, it doesn't actually refresh the ng-repeat and display the new message. How can I do this?
I would suggest some structural changes in your directive.
First of all, why not refer the original array itself instead of referring value at each iteration ??
<message messages="messages">
Then you can actually move ng-repeat part in your directive template, [You must note that since you're using = in message: "=", = binds a local/directive scope property to a parent scope property. So with =, you use the parent model/scope property name as the value of the DOM attribute. ].
Hence your directive will look like :
app.directive("message", function() {
return {
restrict: "E",
scope: {
messages: "="
},
templateUrl: "js/Directives/message.html"
};
});
and the subsequent template will look something like this :
<ul>
<li ng-repeat="message in messages" class="message">{{message.msg}} </li>
</ul>
You can find a demo plunker here
I am building a dropdown menu directive which allows you to optionally attach a function to each item in the list. I know how to pass one function per attribute into the directive, but I'm hoping that there is a way to pass multiple functions.
<dropdown items="['item1', 'item2']" actions="['action1()', 'action2()']"></dropdown>
or better yet:
<dropdown items="[{'item1':action1()}, {'item2':action2()}]"></dropdown>
which could be used to generate:
<dropdown items="['item1', 'item2']" actions="['action1()', 'action2()']">
<a ng-click="action1()">item1</a>
<a ng-click="action2()">item2</a>
</dropdown>
You can use the = object notation for your scope in accepting an array of objects with properties that you can assign to your directive.
DEMO
Controller
.controller('Ctrl', function($scope) {
var action = function() {
window.alert(this.label);
};
$scope.items = [{
label: 'Item 1',
action: action
}, {
label: 'Item 2',
action: action
}, {
label: 'Item 3',
action: action
}, {
label: 'Item 4',
action: action
}];
})
Directive
.directive('dropdown', function() {
return {
restrict: 'E',
scope: {
items: '='
},
template:
'<div ng-repeat="item in items track by $index" ng-click="item.action()">' +
'<a ng-bind="item.label"></a>' +
'</div>'
};
});
index.html
<body ng-controller="Ctrl">
<dropdown items="items"></dropdown>
</body>
to pass any form of function to a directive that does same thing in thesense ike a call back from the directive to execute the function , the method should be as below
First of all use the return scope to contain the functionName : '&' as it is used in passing functions
Then returning it back should look like this from ur template ng-click='functionName({params:values[,params2:value2]})'
as the above would send the param as argument to the calling controller calling the directive
var app = angular.module('testApp', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.items=['value1','value2','value3'];
$scope.items2=['value12','value22','value32'];
$scope.clicked='';
$scope.alert=function(val){
$scope.clicked=val;
}
$scope.alerti=function(val){
$scope.clicked=val+"-Second";
}
});
app.directive('direct', function(){
return {
restrict: 'E',
scope : {
actionTest:'&',
tests:'='
},
// controller: 'ctrl',
template: '<ul><li ng-repeat="test in tests" ng-click="actionTest({val:test})">{{test}} </li></ul>'
}
});
/*
app.controller('ctrl', function($scope){
});*/
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="testApp">
<div ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<p>CLicked : {{clicked}}</p>
<direct tests='items' action-test='alert(val)'></direct>
<!--with a different action function-->
<direct tests='items2' action-test='alerti(val)'></direct>
</div>
</div>
I'd like to define meta data which will dynamically use the correct directive based on a "type" value:
$scope.items = [
{
type: 'directive-one',
value: 'One'
},{
type: 'directive-two',
value: 'Two'
},{
type: 'directive-three',
value: 'Three'
}
];
and then
<li ng-repeat="item in items" {{type}}>
{{value}}
</li>
I've created a jsfiddle here. So far I've had no success
Is this possible? How would I accomplish this?
Here is an alternative way of solving the problem:
Use ngSwitch to map between type and directive.
<li ng-repeat="item in items">
<div ng-switch on="item.type">
<div ng-switch-when="type-one" directive-one>
</div>
<div ng-switch-when="type-two" directive-two>
</div>
<div ng-switch-when="type-three" directive-three>
</div>
</div>
</li>
See jsfiddle
But if you really need to define the directive in the metadata, you can add a directive that will generate the div element with the appropriate directive
angular.module('myApp').directive('dynamicDirective', function($compile) {
return {
restrict: 'A',
link: function (scope, ele) {
//add a child div element that contains the directive specified in the type property
var itemEl = angular.element('<div>').attr(scope.item.type,'');
$compile(itemEl)(scope);
ele.append(itemEl);
}
};
});
See jsfiddle