Wrapping jQuery UI or Bootstrap widgets with Angular directives is not the same as creating Angular widgets.
app.directive('myWidget', function() {
return {
restrict: 'E'
//...
};
}
app.directive('myWidget', function(MyWidgetConfig) {
return {
restrict: 'E',
scope: {
param1: '=',
param2: '='
},
link: function(scope) {
scope.param1 = scope.param1 || MyWidgetConfig.param1;
scope.param2 = scope.param2 || MyWidgetConfig.param2;
}
};
});
app.directive('myWidget', function() {
return {
templateUrl: 'myWidget.tpl.html'
};
});
<div class="combo">
<div class="combo-label"></div> <!-- label would be bad here -->
<div class="combo-input"></div> <!-- input would be bad here -->
<div class="combo-trigger"></div>
</div>
- forms
- form.js
- form.spec.js
- form.tpl.html
- form.css
- input.js
- input.spec.js
- input.tpl.html
- input.css
- calendar
- calendar.js
- calendar.spec.js
- calendar.tpl.html
- calendar.css
- app.js
ShinyWidgetBundle-0.0.1.js
ShinyWidgetBundle-tpl-0.0.1.js
// Directive definition
app.directive('superForm', {
return {
restrict: 'E',
scope: {
onSubmit: '&' // <--- & for binding functions
},
template: '<form><button ng-click="submit()">Submit</button></form>',
link: function(scope) {
scope.submit = function() {
scope.onSubmit({firstName: 'Aaron', lastName: 'Smith'});
};
}
};
});
<!-- Directive usage -->
<super-form onSubmit="submitHandler(firstName, lastName)"></super-form>
// Handler definition
$scope.submitHandler = function(firstName, lastName) {
console.log(firstName + ' ' + lastName); //Prints 'Aaron Smith'
});
// Allow dupes
<div ng-repeat="item in items track by $index">{{item.value}}</div>
// Avoid rewrites (and dupes)
<div ng-repeat="item in items track by item.id">{{item.value}}</div>
Let's reinvent the wheel
<div class="combo">
<div class="combo-input">{{displayValue}}</div>
<div class="combo-trigger" ng-click="showOptions = !showOptions"></div>
<div class="combo-options" ng-show="showOptions">
<div class="combo-option"
ng-repeat="option in options track by option[valueField]"
ng-class="{selected: option[valueField] == value}"
ng-click="onSelectItem(option)">
{{option[displayField]}}
</div>
</div>
</div>
app.directive('combo', function(ComboConfig) {
return {
restrict: 'E',
scope: {
value: '=',
options: '=',
valueField: '=',
displayField: '=',
onChange: '&'
},
templateUrl: 'forms/combo.tpl.html',
link: function($scope, element, attrs, controller) {
//...
}
}
})
$scope.valueField = $scope.valueField || ComboConfig.id;
$scope.displayField = $scope.displayField || ComboConfig.id;
$scope.options = $scope.options || [];
$scope.showOptions = false;
$scope.displayValue = updateDisplayValue();
$scope.$watch('value', updateDisplayValue);
$scope.onSelectItem = function(item) {
$scope.showOptions = false;
$scope.value = item[$scope.valueField];
$scope.onChange({value: item});
};
function updateDisplayValue() {
$scope.displayValue = ''; //Make sure it's reset
if ($scope.value) {
$scope.options.forEach(function(option) {
if (option[$scope.valueField] === $scope.value) {
$scope.displayValue = option[$scope.displayField];
}
});
}
}
.combo {
position: relative;
}
.combo-input {
border: 1px solid #555; padding: 4px;
}
.combo-trigger {
border: 1px solid #555; border-left-width: 0px;
}
.combo-options {
position: absolute; top: 30px; border: 1px solid #555;
}
.combo-option.selected {
background-color: #00c; color: #fff;
}
<combo value="country" options="countries"
on-change="onCountryChange(value)"></combo>
<!-- our AutoComplete combo template -->
<div class="combo autocomplete">
<autocomplete-field></autocomplete-field>
<options-list></options-list>
</div>
<!-- our standard combobox template -->
<div class="combo">
<combo-field></combo-field>
<options-list></options-list>
</div>