Get one item from a list in parent scope - angularjs

I have the following Angular controllers:
function TagListController($scope) {
$scope.model = {
tags: ['tag 1', 'tag 2', 'tag 3' ],
template: 'list'
}
$scope.showTemplate = function (template) {
$scope.model.template = template;
};
}
function TagEditController($scope) {
$scope.tagToEdit = $scope.$parent.model ???
}
And I have the following HTML to show a list of tags and to edit a tag:
<ul ng-if="model.template == 'list'" ng-controller="TagListController">
<li data-ng-repeat="tag in model.tags">
<span data-ng-bind="tag.name"></span></br>
<a href="" data-ng-click="show('edit')"</a>
</li>
</ul>
<script type="text/ng-template" id="edit">
<div ng-controller="TagEditController">
Edit template
</div>
</script>
<div ng-if="model.template == 'edit'" ng-include="'edit'"></div>
Using model.template I am able to show the Edit template.
But how can I, in EditTagController, use the tag which Edit link was clicked?
I know it will be one of the items in $scope.$parent.model.tags.
I just don't know how to select it and the best way to select it.

This would be a good place to use a factory or service.
See this jsBin
You want to store common data inside of your factory instead of dealing with $parent or $rootScope.
You could create a factory like this:
function tagService() {
var observerCallbacks = [];
var currentTag;
function getCurrentTag() {
return currentTag;
}
function setCurrentTag(tag) {
currentTag = tag;
notifyObservers();
}
function notifyObservers() {
angular.forEach(observerCallbacks, function(callback) {
callback();
});
}
function registerObserverCallback(callback) {
this.observerCallbacks.push(callback);
notifyObservers();
}
return {
getCurrentTag: getCurrentTag,
setCurrentTag: setCurrentTag,
registerObserverCallback: registerObserverCallback,
notifyObservers: notifyObservers
};
}
Here, I'm also using the observer pattern to notify anybody who is listening for changes any time setCurrentTag is called. That way, if you change tags, both controllers know.
Your TagListController might look like:
function TagListController($scope, tagService) {
$scope.model = {
tags: ['tag 1', 'tag 2', 'tag 3' ],
template: 'list'
};
$scope.editTag = function(tag) {
tagService.setCurrentTag(tag);
$scope.model.template = 'edit';
};
}
And your TagEditController like:
function TagEditController($scope, tagService) {
tagService.registerObserverCallback(function() {
$scope.tagToEdit = tagService.getCurrentTag();
});
}

How about using Angular routing? You could set up a route like "yourapp/tags/{tag}" to your EditTagController and that way you will get the current tag as a parameter.
Something like this

Related

Angular 1.5 ng-change on select element in component triggering previous response

I'm just starting to play with components in Angular 1.5.x and have created one for a select box on a form - I pass in the field, list and label to the component and it creates the form 'part' consisting of the label and select box with the correct options - so far, so good.
Now I want to implement an ng-change on the select so I am passing in the function I want to use for this. The problem I have is that the function is triggering with the old value for the select not the new value. I can see that the function is triggering prior to the actual change. If I put the change function within the component change event it registers correctly, but not using a passed in function.
I have created a cut-down fiddle at https://jsfiddle.net/7gd3m2k0/
<div ng-app="demoApp">
<div ng-controller="RoleController as ctrl">
<nac-select
field="ctrl.MemberRole.record.member"
list="ctrl.Lists.Member"
label="Member"
on-change="ctrl.MemberRole.changeMember();"></nac-select>
<div ng-bind="ctrl.MemberRole.record.member.name"></div>
</div>
</div>
angular.module('demoApp', [])
.component('nacSelect', nacSelect)
.controller('RoleController', roleController)
var nacSelect = {
bindings: {
field: '=',
list: '<',
label: '#label',
onChange: '&'
},
controller: function () {
var ctrl = this;
ctrl.change = function () {
alert(ctrl.field.name); //gives new selection
ctrl.onChange(); //gives previous selection
}
},
template: `
<label>{{$ctrl.label}}</label>
<select ng-model="$ctrl.field" ng-options="r as r.name for r in $ctrl.list" ng-change="$ctrl.change();">
<option value="">(Please Select)</option>
</select>
`
};
var roleController = function(){
var ctrl = this;
ctrl.Lists = {
Member: [
{id: 1, name: 'Fred Smith'},
{id: 2, name: 'Jenny Jones'},
{id: 3, name: 'Jane Doe'}
]
};
ctrl.MemberRole = {
record: {
member: null
},
changeMember: function(){
alert(ctrl.MemberRole.record.member.name);
}
};
};
I guess I am missing something simple, but I can't figure it out. Thank you for your assistance
You need to pass in variable that you want to alert in the first controller, check this:
https://jsfiddle.net/pegla/7gd3m2k0/1/
so your function would look like this:
changeMember: function(name){
alert(name);
}
when you're using nac-select
<nac-select field="ctrl.MemberRole.record.member" list="ctrl.Lists.Member" label="Member" on-change="ctrl.MemberRole.changeMember(name);"></nac-select>
and in the end in the nac-select:
<select ng-model="$ctrl.field" ng-options="r as r.name for r in $ctrl.list | orderBy: 'name'" ng-required="$ctrl.req" ng-if="!$ctrl.list.processing" ng-change="$ctrl.onChange($ctrl.field)">
or if you want to pass in object:
<nac-select field="ctrl.MemberRole.record.member" list="ctrl.Lists.Member" label="Member" on-change="ctrl.MemberRole.changeMember({id, name});"></nac-select>
then your changeMember can look like this:
changeMember: function(obj){
alert(`${obj.name} ${obj.id}`);
}
New fiddle:
https://jsfiddle.net/pegla/7gd3m2k0/2/

Passing a binding to transcluded scope in component

In AngularJS 1.5, I want to pass a binding from a component into the (multi-slot) transcluded scope - for a reference in the template (in either one specific or all of them - no either way is fine).
This is for creating a generic custom-select list
// Component
.component('mySelect', {
bind: {
collection: '<'
},
transclude:{
header: 'mySelectHeader',
item: 'mySelectItem'
},
templateUrl: 'my-select-template',
controller: function(){
.....
}
});
...
// Component template
<script id="my-select-template" type="text/ng-template">
<ol>
<li ng-transclude="header"> </li>
<li ng-transclude="item"
ng-click="$ctrl.select($item)"
ng-repeat"$item in $ctrl.collection">
</li>
</ol>
</script>
...
// Example usage
<my-select collection="[{id: 1, name: "John"}, {id: 2, name: "Erik"}, ... ]>
<my-select-head></my-select-head>
<!-- Reference to $item from ng-repeate="" in component -->
<my-select-item>{{$item.id}}: {{$item.name}}</my-select-item>
</my-select>
Is this possible from a .component()? with custom-directives for the transclusion ?
In your parent component my-select keep a variable like "selectedItem"
In your child component my-select-item, require your parent component like below
require: {
mySelect: '^mySelect'
}
And in your my-select-item component's controller, to access your parent component
$onInit = () => {
this.mySelectedItem= this.mySelect.selectedItem; // to use it inside my-select-item component.
};
select($item) {
this.mySelect.selectedItem = $item; // to change the selectedItem value stored in parent component
}
So that the selected item is now accessible from
<my-select-item>{{selectedItem.id}}: {{selectedItem.name}}</my-select-item>
I ran into this problem as well, and building upon salih's answer, I came up with a solution (disclaimer--see bottom: I don't think this is necessarily the best approach to your problem). it involves creating a stubbed out component for use in the mySelect component, as follows:
.component('item', {
require: { mySelect: '^mySelect' },
bind: { item: '<' }
})
then, tweaking your template:
<script id="my-select-template" type="text/ng-template">
<ol>
<li ng-transclude="header"> </li>
<li ng-click="$ctrl.select($item)"
ng-repeat"$item in $ctrl.collection">
<item item="$item" ng-transclude="item"></item>
</li>
</ol>
</script>
this will mean there's always an item component with the value bound to it. now, you can use it as a require in a custom component:
.component('myItemComponent', {
require: {
itemCtrl: '^item',
}
template: '<span>{{$ctrl.item.id}}: {{$ctrl.item.name}}</span>',
controller: function() {
var ctrl = this;
ctrl.$onInit = function() {
ctrl.item = ctrl.itemCtrl.item;
}
}
});
and to use it:
<my-select collection="[{id: 1, name: "John"}, {id: 2, name: "Erik"}, ... ]>
<my-select-head></my-select-head>
<my-select-item>
<my-item-component></my-item-component>
</my-select-item>
</my-select>
after I implemented this, I actually decided to change my strategy; this might work for you as well. instead of using a transclude, I passed in a formatting function, i.e.:
.component('mySelect', {
bind: {
collection: '<',
customFormat: '&?'
},
transclude:{
header: 'mySelectHeader'
},
templateUrl: 'my-select-template',
controller: function(){
var ctrl = this;
ctrl.format = function(item) {
if(ctrl.customFormat) {
return customFormat({item: item});
} else {
//default
return item;
}
}
.....
}
});
then in the template, just use:
<script id="my-select-template" type="text/ng-template">
<ol>
<li ng-transclude="header"> </li>
<li ng-click="$ctrl.select($item)"
ng-repeat"$item in $ctrl.collection"
ng-bind="::$ctrl.format($item)">
</li>
</ol>
</script>
let me know if you have any feedback or questions!

AngularJS : How to add a new object into array while using factory and directives

Trying to simulate a hotel cart.
Newbie here
Questions
1. How to add an item to orders when clicked on corresponding Add button
2. Is it correct to use a factory for serving both menuitems for menu directive and orderItems for cart directive
3. On click of add button, where should the to be called add function be written, in the factory or in the directive's controller
4. Is there any way to better this code and its logic?
For those who wish to see the plunkr demo can view the same here
HTML snippet
<menu></menu>
JS snippet
angular.module('myApp',[])
.factory('menuItems',function(){
return {
list:function(){
var items = [{'name':'kabab'},
{'name':'chicken'},
{'name':'egg'},
{'name':'noodles'}];
return items
}
};
})
.factory('cartItems',function(){
var orders = [];
return orders;
})
.directive('menu',function(){
return {
restrict:'E',
template:"<ul><li ng-repeat='item in menuItems'>"+
'{{item.name}}' +
"</li></ul>",
scope:{},
controllerAs:'menuCtrl',
controller:function($scope, menuItems){
console.log("I am in menuDirective and outputting menuItems")
console.log(menuItems);
$scope.menuItems = menuItems.list();
},
link:function(){
}
}
})
.directive('cart',function(){
return{
restrict:'E',
template:"<ul><li ng-repeat='order in cartItems'>"+
'{{order.name}}' +
"</li></ul>",
scope:{},
controller:function($scope,cartItems){
$scope.cartItems = cartItems.list();
},
link:function(){
}}
})
Plunker Demo
I think this is a fine way to do it. Since you need to access the same dataset from multiple directives, it makes sense to me to put the methods and data into a factory.
HTML:
<body ng-controller="MainCtrl">
<menu></menu>
<br />Cart:<br />
<cart></cart>
</body>
JS:
angular.module('plunker',[])
.controller('MainCtrl', function() {
})
.factory('menuItems',function(){
return {
list:function(){
var items = [{'name':'kabab'},
{'name':'chicken'},
{'name':'egg'},
{'name':'noodles'}];
return items
}
};
})
.factory('cartItems',function(){
return {
orders: [],
add: function(item) {
this.orders.push(item)
}
}
//return this.orders;
})
.directive('menu',function(cartItems){
return {
restrict:'E',
template:"<ul><li ng-repeat='item in menuItems'>"+
'{{item.name}}' +
"<button ng-click='addItem(item.name)'>Add</button></li></ul>",
scope:{},
controllerAs:'menuCtrl',
controller:function($scope, menuItems){
console.log("I am in menuDirective and outputting menuItems")
console.log(menuItems);
$scope.menuItems = menuItems.list();
$scope.addItem = function(item) {
cartItems.add(item);
console.log(cartItems.orders)
}
},
link:function(){
}
}
})
.directive('cart',function(){
return{
restrict:'E',
template:"<ul><li ng-repeat='order in cartItems track by $index'>"+
'{{order}}' +
"</li></ul>",
scope:{},
controller:function($scope,cartItems){
$scope.cartItems = cartItems.orders;
},
link:function(){
}}
})
Any methods relating to the orders array should be put in the factory. Your factory should encapsulate all logic related to that particular 'thing'. Keeping the logic out of your directives gives you good abstraction, so if you need to change something, you know where all the logic is kept, rather than spread out in a bunch of directives. So if you want to add an 'empty cart' method, or a 'delete from cart' method, I would put those into the factory, operate directly on the orders array, and return the updated array to whatever is calling the methods.

Good way to dynamically open / close a popover (or tooltip) using angular, based on expression?

I have a form that is wired into angular, using it for validation. I am able to display error messages using ng-show directives like so:
<span ng-show="t3.f.needsAttention(f.fieldName)" ng-cloak>
<span ng-show="f.fieldName.$error.required && !f.fieldName.$viewValue">
This field is required.
</span>
</span>
.. where f is the form, and t3 comes from a custom directive on the form which detects whether a submission was attempted, and contains functions for checking the validity of fields.
What I am trying to accomplish is to display validation message(s) inside a popover instead. Either bootstrap's native popover, or the popover from UI Bootstrap, I have both loaded. I may also consider AngularStrap if it is easier to do it using that lib.
What I'm struggling with right now is the nature of popovers in general -- they autodisplay based on user events like click, mouseenter, blur, etc. What I want to do is show & hide the popover(s) based on the same functions in the ng-show attributes above. So that when the expression returns false hide it, and when it returns true, show it.
I know bootstrap has the .popover('show') for this, but I'm not supposed to tell angular anything about the dom, so I'm not sure how I would get access to $(element).popover() if doing this in a custom form controller function. Am I missing something?
Update
The solution mentioned in the duplicate vote still only shows the popover on mouseenter. I want to force it to display, as if doing $('#popover_id').popover('show').
You can also build your own extended triggers. This will apply to both Tooltip and Popover.
First extend the Tooltip triggers as follows:
// define additional triggers on Tooltip and Popover
app.config(['$tooltipProvider', function($tooltipProvider){
$tooltipProvider.setTriggers({
'show': 'hide'
});
}]);
Then define the trigger on the HTML tag like this:
<div id="RegisterHelp" popover-trigger="show" popover-placement="left" popover="{{ 'Login or register here'}}">
And now you can call hide and show from JavaScript, this is a show in 3 seconds.
$("#RegisterHelp").trigger('show');
//Close the info again
$timeout(function () {
$("#RegisterHelp").trigger('hide');
}, 3000);
As it turns out, it's not very difficult to decorate either the ui-bootstrap tooltip or the popover with a custom directive. This is written in typescript, but the javascript parts of it should be obvious. This single piece of code works to decorate either a tooltip or a popover:
'use strict';
module App.Directives.TooltipToggle {
export interface DirectiveSettings {
directiveName: string;
directive: any[];
directiveConfig?: any[];
}
export function directiveSettings(tooltipOrPopover = 'tooltip'): DirectiveSettings {
var directiveName = tooltipOrPopover;
// events to handle show & hide of the tooltip or popover
var showEvent = 'show-' + directiveName;
var hideEvent = 'hide-' + directiveName;
// set up custom triggers
var directiveConfig = ['$tooltipProvider', ($tooltipProvider: ng.ui.bootstrap.ITooltipProvider): void => {
var trigger = {};
trigger[showEvent] = hideEvent;
$tooltipProvider.setTriggers(trigger);
}];
var directiveFactory = (): any[] => {
return ['$timeout', ($timeout: ng.ITimeoutService): ng.IDirective => {
var d: ng.IDirective = {
name: directiveName,
restrict: 'A',
link: (scope: ng.IScope, element: JQuery, attr: ng.IAttributes) => {
if (angular.isUndefined(attr[directiveName + 'Toggle'])) return;
// set the trigger to the custom show trigger
attr[directiveName + 'Trigger'] = showEvent;
// redraw the popover when responsive UI moves its source
var redrawPromise: ng.IPromise<void>;
$(window).on('resize', (): void => {
if (redrawPromise) $timeout.cancel(redrawPromise);
redrawPromise = $timeout((): void => {
if (!scope['tt_isOpen']) return;
element.triggerHandler(hideEvent);
element.triggerHandler(showEvent);
}, 100);
});
scope.$watch(attr[directiveName + 'Toggle'], (value: boolean): void => {
if (value && !scope['tt_isOpen']) {
// tooltip provider will call scope.$apply, so need to get out of this digest cycle first
$timeout((): void => {
element.triggerHandler(showEvent);
});
}
else if (!value && scope['tt_isOpen']) {
$timeout((): void => {
element.triggerHandler(hideEvent);
});
}
});
}
};
return d;
}];
};
var directive = directiveFactory();
var directiveSettings: DirectiveSettings = {
directiveName: directiveName,
directive: directive,
directiveConfig: directiveConfig,
};
return directiveSettings;
}
}
With this single piece of code, you can set up programmatic hide and show of either a tooltip or popover like so:
var tooltipToggle = App.Directives.TooltipToggle.directiveSettings();
var popoverToggle = App.Directives.TooltipToggle.directiveSettings('popover');
var myModule = angular.module('my-mod', ['ui.bootstrap.popover', 'ui.bootstrap.tpls'])
.directive(tooltipToggle.directiveName, tooltipToggle.directive)
.config(tooltipToggle.directiveConfig)
.directive(popoverToggle.directiveName, popoverToggle.directive)
.config(popoverToggle.directiveConfig);
Usage:
<span tooltip="This field is required."
tooltip-toggle="formName.fieldName.$error.required"
tooltip-animation="false" tooltip-placement="right"></span>
or
<span popover="This field is required."
popover-toggle="formName.fieldName.$error.required"
popover-animation="false" popover-placement="right"></span>
So we are reusing everything else that comes with the ui-bootstrap tooltip or popover, and only implementing the -toggle attribute. The decorative directive watches that attribute, and fires custom events to show or hide, which are then handled by the ui-bootstrap tooltip provider.
Update:
Since this answer seems to be helping others, here is the code written as javascript (the above typescript more or less compiles to this javascript):
'use strict';
function directiveSettings(tooltipOrPopover) {
if (typeof tooltipOrPopover === "undefined") {
tooltipOrPopover = 'tooltip';
}
var directiveName = tooltipOrPopover;
// events to handle show & hide of the tooltip or popover
var showEvent = 'show-' + directiveName;
var hideEvent = 'hide-' + directiveName;
// set up custom triggers
var directiveConfig = ['$tooltipProvider', function ($tooltipProvider) {
var trigger = {};
trigger[showEvent] = hideEvent;
$tooltipProvider.setTriggers(trigger);
}];
var directiveFactory = function() {
return ['$timeout', function($timeout) {
var d = {
name: directiveName,
restrict: 'A',
link: function(scope, element, attr) {
if (angular.isUndefined(attr[directiveName + 'Toggle']))
return;
// set the trigger to the custom show trigger
attr[directiveName + 'Trigger'] = showEvent;
// redraw the popover when responsive UI moves its source
var redrawPromise;
$(window).on('resize', function() {
if (redrawPromise) $timeout.cancel(redrawPromise);
redrawPromise = $timeout(function() {
if (!scope['tt_isOpen']) return;
element.triggerHandler(hideEvent);
element.triggerHandler(showEvent);
}, 100);
});
scope.$watch(attr[directiveName + 'Toggle'], function(value) {
if (value && !scope['tt_isOpen']) {
// tooltip provider will call scope.$apply, so need to get out of this digest cycle first
$timeout(function() {
element.triggerHandler(showEvent);
});
}
else if (!value && scope['tt_isOpen']) {
$timeout(function() {
element.triggerHandler(hideEvent);
});
}
});
}
};
return d;
}];
};
var directive = directiveFactory();
var directiveSettings = {
directiveName: directiveName,
directive: directive,
directiveConfig: directiveConfig,
};
return directiveSettings;
}
For ui.bootstrap 0.13.4 and newer:
A new parameter (popover-is-open) was introduced to control popovers in the official ui.bootstrap repo. This is how you use it in the latest version:
<a uib-popover="Hello world!" popover-is-open="isOpen" ng-click="isOpen = !isOpen">
Click me to show the popover!
</a>
For ui.bootstrap 0.13.3 and older:
I just published a small directive that adds more control over popovers on GitHub: https://github.com/Elijen/angular-popover-toggle
You can use a scope variable to show/hide the popover using popover-toggle="variable" directive like this:
<span popover="Hello world!" popover-toggle="isOpen">
Popover here
</span>
Here is a demo Plunkr: http://plnkr.co/edit/QeQqqEJAu1dCuDtSvomD?p=preview
My approach:
Track the state of the popover in the model
Change this state per element using the appropriate directives.
The idea being to leave the DOM manipulation to the directives.
I have put together a fiddle that I hope gives a better explain, but you'll find much more sophisticated solutions in UI Bootstrap which you mentioned.
jsfiddle
Markup:
<div ng-repeat="element in elements" class="element">
<!-- Only want to show a popup if the element has an error and is being hovered -->
<div class="popover" ng-show="element.hovered && element.error" ng-style>Popover</div>
<div class="popoverable" ng-mouseEnter="popoverShow(element)" ng-mouseLeave="popoverHide(element)">
{{ element.name }}
</div>
</div>
JS:
function DemoCtrl($scope)
{
$scope.elements = [
{name: 'Element1 (Error)', error: true, hovered: false},
{name: 'Element2 (no error)', error: false, hovered: false},
{name: 'Element3 (Error)', error: true, hovered: false},
{name: 'Element4 (no error)', error: false, hovered: false},
{name: 'Element5 (Error)', error: true, hovered: false},
];
$scope.popoverShow = function(element)
{
element.hovered = true;
}
$scope.popoverHide = function(element)
{
element.hovered = false
}
}
For others coming here, as of the 0.13.4 release, we have added the ability to programmatically open and close popovers via the *-is-open attribute on both tooltips and popovers in the Angular UI Bootstrap library. Thus, there is no longer any reason to have to roll your own code/solution.
From Michael Stramel's answer, but with a full angularJS solution:
// define additional triggers on Tooltip and Popover
app.config(['$tooltipProvider', function($tooltipProvider){
$tooltipProvider.setTriggers({
'show': 'hide'
});
}])
Now add this directive:
app.directive('ntTriggerIf', ['$timeout',
function ($timeout) {
/*
Intended use:
<div nt-trigger-if={ 'triggerName':{{someCodition === SomeValue}},'anotherTriggerName':{{someOtherCodition === someOtherValue}} } ></div>
*/
return {
restrict: 'A',
link: function (scope, element, attrs) {
attrs.$observe('ntTriggerIf', function (val) {
try {
var ob_options = JSON.parse(attrs.ntTriggerIf.split("'").join('"') || "");
}
catch (e) {
return
}
$timeout(function () {
for (var st_name in ob_options) {
var condition = ob_options[st_name];
if (condition) {
element.trigger(st_name);
}
}
})
})
}
}
}])
Then in your markup:
<span tooltip-trigger="show" tooltip="Login or register here" nt-trigger-if="{'show':{{ (errorConidtion) }}, 'hide':{{ !(errorConidtion) }} }"></span>

Get Selected Object Of Kendo Drop Down List

I am using the Kendo Drop Down List. More specifically, I'm using Kendo Angular directives. Currently, I have the following in my markup:
<input id='myDropDownList' kendo-drop-down-list ng-model="selectedSport" k-data-source="sports" k-data-text-field="'name'" />
<button ng-click='send()'>Submit</button>
My controller has the following:
$scope.selectedSport = null;
$scope.sports: [
{ id: 1, name: 'Basketball' },
{ id: 2, name: 'Football' },
{ id: 3, name: 'Tennis' }
];
$scope.send = function () {
alert($scope.selectedSport);
};
When I run this code, I get the selectedSport ID. However, I want the entire object. Every other StackOverflow post I've found uses retrieves the ID. For the life of me, I can't figure out how to get the object. Does anyone know how to get the selected JSON object instead of just the id?
Thanks!
This answer is probably outdated for current versions of the Kendo Angular bindings.
As mentioned in hally9k's answer, there is now an attribute k-ng-model that can handle this, so you would use
k-ng-model="selectedSport"
in place of
ng-model="selectedSport"
Previous answer below; this may or may not still be relevant in case you're using an older version of Kendo UI:
I don't think you can configure the kendo widget to store the dataItem directly - underneath it all is still a <select> with a primitive value. So you'll probably have to get the dataItem from the widget's data source, e.g. like this:
HTML:
<div ng-controller="MyController">
<select id='myDropDownList' kendo-drop-down-list ng-model="selectedSport" k-data-source="sports" k-data-value-field="'id'" k-data-text-field="'name'"></select>
<button ng-click='send()'>Submit</button>
</div>
JS:
function MyController($scope) {
$scope.selectedSport = null;
$scope.sports = new kendo.data.DataSource({
data: [{
id: 1,
name: 'Basketball'
}, {
id: 2,
name: 'Football'
}, {
id: 3,
name: 'Tennis'
}]
});
$scope.send = function () {
var dataItem = $scope.sports.get($scope.selectedSport);
console.log(dataItem);
};
}
You could, however, create your own directive for kendoDropDownList which uses a k-data-item attribute (for example) and use it like this:
HTML:
<select id='date' k-ddl k-data-source="sports" k-data-text-field="name" k-data-item="dataItem">
JS:
var app = angular.module('Sample', ['kendo.directives']).directive("kDdl", function () {
return {
link: function (scope, element, attrs) {
$(element).kendoDropDownList({
dataTextField: attrs.kDataTextField,
dataValueField: "id",
dataSource: scope[attrs.kDataSource],
change: function () {
var that = this;
var item = that.dataItem();
scope.$apply(function () {
scope[attrs.kDataItem] = item.toJSON();
});
}
});
}
};
});
function MyController($scope) {
$scope.sports = [{
id: 1,
name: 'Basketball'
}, {
id: 2,
name: 'Football'
}, {
id: 3,
name: 'Tennis'
}];
$scope.dataItem = $scope.sports[0];
$scope.send = function () {
console.log($scope.dataItem);
};
}
That way, you could keep the controller free from Kendo UI DataSource-specific code and instead only work with JS data types. (see JSBin)
Using k-ng-model will bind the dataItem instead of just the text value:
<input id='myDropDownList' kendo-drop-down-list k-ng-model="selectedSport" k-data-source="sports" k-data-text-field="'name'" />
I know this is an old question, but you could use the select event of the dropdownlist to get the underlying json object:
select: function (e) {
var item = this.dataItem(e.item.index());
...
}
You would then store the json object (item variable above) from the select event so that you can get to it from your submit method. There is probably a way to get the selected json object without having to use the select event as well.
The proper way to get the text value is to use the 'k-select' event of Kendos dropdownlist:
<select kendo-drop-down-list k-select="vm.test" k-data-text-field="'groupName'" k-data-value-field="'id'" k-data-source="vm.groupList" ng-model="vm.groupId"></select>
Then in your angular controller expose the 'test' function (example assumes you are using 'controller as vm'):
function DocumentTypeController() {
var vm = this;
vm.test = test;
vm.groupId = null;
function test(dropdown) {
alert('text is:' + dropdown.item.text());
}
}
I hope that helps.

Resources