I am new to angularjs and working to directive for a dropdown but having problem to select initial value. I have to pass the Id of the option to select as an attribute to the directive. I am setting the attribute value in a scope variable which I then use in ng-Init.
Here is my directive code:
export class ChoiceGroup
{
constructor ()
{
var directive: ng.IDirective = {};
directive.restrict = "E";
directive.replace = true;
directive.template = '<div><select name="cmbCG" ng-model="dataSel" ng-options="c.DisplayName for c in data"></select></div>';
directive.link = function ($scope: any, element: JQuery, attributes: any) {
var injector = angular.element(document).injector();
var key = attributes.key;
var cgCacheService: ChoiceGroupsCacheService;
seCGCacheService = injector.get('seChoiceGroupsCacheService');
var values: Array<ChoiceValue>;
values = seCGCacheService.GetChoiceValues(key);
$scope.data = values;
if (attributes.selectedvalue) {
$scope.selectedvalue = values[attributes.selectedvalue];
}
}
return directive;
}
The code is in Typescript. Here is HTML:
<choicegroupcombo key="RecurrenceFrequency" selectedvalue="3"></choicegroupcombo>
If I hardcode the value of dataSel ie ng-init="dataSel=3" then it works fine but when I set to scope variable then it does not work. So how can I fix the issue.
EDIT
Solved. I have updated the code accordingly.
I think this might be a classic case of "over-engineering".
Your code doesn't seem to be trying to do anything other than what a standard select box does.
Try this instead:
app = angular.module('app', [])
app.controller 'MainCtrl', ($scope) ->
# $scope.values = ChoiceGroupsCacheService(key)
$scope.values = [
{ id: 0, label: 'Zero' }
{ id: 1, label: 'One' }
{ id: 2, label: 'Two' }
{ id: 3, label: 'Three' }
]
$scope.number = 2
and the view:
<select ng-model="number" ng-options="item.id as item.label for item in values"></select>
Code is in coffeescript:
Here's a plunkr: http://plnkr.co/edit/C6qmUoJ6HjsAT69oavRg
Related
I have two directives in my code where parent directive's template contains child directive. The child directive is passed an attribute called "items" and it calls a function which will be returning a promise.
The child directive's controller then takes that items promise and does a 'then' to get the results. These results are then to be displayed in the dropdown.
I have been working with this code for a while now and am not able to figure out the warning I am getting. Also, I am not getting the right results.
Basically, when you click on Change Value button, it will return a different array. Odd numbers and event numbers provide different arrays (this was so I could simulate change to the model).
Below is the code and here is a link to the Codepen
Parent Controller
app.controller("mainCtrl", function($scope, $q) {
var that = this;
that.r = 0;
var i = [{ name: "toronto" }, { name: "chicago" }, { name: "new york" }];
var j = [{ name: "Martin" }, { name: "Stephanie" }, { name: "Kirk" }];
this.getItems = function () {
var deferred = $q.defer();
if (that.r % 2 == 0) {
console.log("getItems: i returned");
deferred.resolve(i);
} else {
console.log("getItems: j returned");
deferred.resolve(j);
}
return deferred.promise;
};
this.changeVal = function() {
that.r += 1;
console.log(that.r);
};
});
Parent Directive
app.directive("parentDirective", function() {
return {
template:
'<child-directive items="ct.getItems()"></child-directive><button ng-click="ct.changeVal()">Change Value</button>',
controller: "mainCtrl",
controllerAs: "ct",
scope: {}
};
});
Child Controller
app.controller("childCtrl", function($scope) {
$scope.name = "Child controller";
$scope.returnedItems =[];
$scope.items.then(function(result){
console.log("Child controller THEN from promise executed");
$scope.returnedItems = result;
});
});
Child Directive
app.directive("childDirective", function() {
return {
template:
'<select ng-model="selectedAction" ng-options="x.name for x in returnedItems"><option value="">Select</option></select>',
controller: "childCtrl",
scope: {
items: "<"
}
};
});
when I run the code above, I do get the drop-down populated. But it doesn't change after.
Appreciate any help on this. Thanks!
At the part in your child directive here,
items="ct.getItems()"
You are giving the child directive's scope the result of that function. In this case, a promise. When this promise gets resolved your child scope sets the ng-options to the result as expected. However subsequent calls to ct.getItems() creates a new promise that your child directive knows nothing about.
In my opinion, the cleanest way to get your results into the child is to pass the items array into the child directive. And whenever getItems() is called from the parent directive, update the results array. It simplifies a lot of the code. Here's your modified code. The main thing to note is that the child directive binds to currentItems array instead of the promise, and the array is updated whenever getItems() is called.
var app = angular.module("testApp", []);
app.controller("mainCtrl", function($scope, $q) {
var that = this;
var deferred = $q.defer();
that.r = 0;
var i = [{ name: "toronto" }, { name: "chicago" }, { name: "new york" }];
var j = [{ name: "Martin" }, { name: "Stephanie" }, { name: "Kirk" }];
that.currentItems = i;
this.getItems = function () {
if (that.r % 2 == 0) {
console.log("getItems: i returned");
that.currentItems = i;
deferred.resolve(i);
} else {
console.log("getItems: j returned");
that.currentItems = j;
deferred.resolve(j);
}
return deferred.promise;
};
this.changeVal = function() {
that.r += 1;
this.getItems();
console.log(that.r);
};
});
app.directive("parentDirective", function() {
return {
template:
'<child-directive items="ct.currentItems"></child-directive><button ng-click="ct.changeVal()">Change Value</button>',
controller: "mainCtrl",
controllerAs: "ct",
scope: {}
};
});
app.controller("childCtrl", function($scope) {
$scope.name = "Child controller";
});
app.directive("childDirective", function() {
return {
template:
'<select ng-model="selectedAction" ng-options="x.name for x in items"><option value="">Select</option></select>',
controller: "childCtrl",
scope: {
items: "<"
}
};
});
Heres a plunker using your example
I'm super new to Angular and JS in general. Basically I have an array thats stored in a var inside a factory and I want that entire array (this.insights) to get imported(?) into my directive.
I believe I need to do something like scope.insights = [];
var Piece = function (parameters) {
this.thing = null;
this.that = null;
this.insights = [
{
id: 1,
}
{
id: 2,
}
];
}
Inject this factory in directive same way you inject other services.
app.directive('helloWorld', function(Piece) {
return {
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>',
controller: function(){
var kek = Piece.insights;
}
};
});
I have a directive that creates some input fields and links them to the scope with ngModel. When the user of the directive creates this in the HTML file:
<div tk-quick-form="formStructure" form-data="formData" id="main_form" ></div>
and this in the controller:
$scope.formStructure = [
{
fieldName: 'name',
type: 'string'
}
];
Then an input field will be created with ngModel linking in to formData.name.
The directive works as planned, but I don't know how to test for it in Jasmine.
This is what I'm doing so far:
Under the it function:
$rootScope.formStructure = [
{
fieldName: 'name',
type: 'string'
}
];
var element = $compile('<div tk-quick-form="formStructure" form-data="formData" id="main_form" ></div>"')($rootScope);
$(element).find("input#name").val("set")
dump($(element).find("input#name").val()) // outputs "set"
expect($rootScope.formData.name).toBe("set"); //outputs Expected undefined to have value 'set'
//(although in manual testing $scope.formData.name is actually set because the input field contains ng-model="formData.name")
$rootScope.$digest();
How should I write this test?
As for me you were doing everything right, except couple of things. You should have called $rootScope.$digest() before expect. Also, you have to trigger 'input' with .triggerHandler('input'), so model will get updated.
describe('tkQuickForm', function () {
beforeEach(module('tkQuickForm'));
beforeEach(inject(function ($rootScope, $compile) {
this.$rootScope = $rootScope;
this.scope = $rootScope.$new();
this.$compile = $compile;
}));
it('should pass dummy test', function () {
expect(true).toBe(true);
});
it('should link ng-model to formData', function() {
this.scope.formStructure = [
{
fieldName: 'name',
type: 'string'
}
];
var element = this.$compile(`
<div tk-quick-form="formStructure" form-data="formData" id="main_form"></div>"
`)(this.scope);
this.scope.$digest(); // call digest first
var input = element.find("input")[0];
angular.element(input).val('set').triggerHandler('input');
expect(this.scope.formData.name).toBe("set");
});
});
Checked with "angular": "~1.5.0". All specs are OK.
Related pull-request
I have a specific scenario for a AngularJS directive:
Normally the directive should inherit the default scope
But for some specific scenarios I'd like to replace all values in $scope.myValues with myValues (object loaded from a web-service)
I cannot change in this scenario the main-scope because this is owned by another application (more or less a plugin-mechanism).
Thanks & Regards
Stefan
If think I have found the solution:
Sample Html:
<wi-view data-layout="{{passLayout}}"></wi-view>
<hr />
Original property: {{layout.property1}}
Sample Controller:
app.controller('wiController', function($scope) {
// Simulating the original scope values
$scope.layout = {};
$scope.layout.property1 = 'Original Value';
// New scope values, just here for binding it to the controller
var passLayout = {};
passLayout.property1 = 'Value Overwritten';
passLayout.property2 = 'Another Property';
$scope.passLayout = passLayout;
});
Sample Directive:
app.directive('wiView', function () {
var linkFunction = function(scope, elems, attrs) {
if (attrs.layout !== undefined) {
scope.layout = angular.fromJson(attrs.layout);
}
};
return {
restrict: "E",
scope: true,
priority: 0,
link: linkFunction,
template: '<div>Hello, {{layout.property1}}!</div>'
};
});
I can't seem to get selects working with Angular directives! I have two selects, both inside a directive. I would like for the first select to determine the available options for the second select.
Here's a fiddle:
http://jsfiddle.net/jordannpotter/hfyUa/
Select "Baz" from the "Secondary Select"
Select "First" from the "Primary Select"
Notice that the "Secondary Select" goes blank!!
Of course, if you comment out the directive code (lines 3-9), it works perfectly.
What's going on here, and how do I fix it??
So what you have happening is that the scope of your directive is detaching you from the scope of your controller and you need to add an object level prior to the primary and secondary variables.
var app = angular.module('myApp', [])
app.directive('awesomeDirective', function () {
return {
restrict: 'E',
transclude: true,
template: '<div class="awesome" ng-transclude></div>'
}
});
AwesomeController = function ($scope, $timeout) {
$scope.options = {};
updateAllowedSecondaryOptions = function () {
if ($scope.options.primary == 'primaryOption1') {
$scope.secondaryOptions = [
{value: 'foo', title: 'Foo'},
{value: 'bar', title: 'Bar'},
{value: 'baz', title: 'Baz'}]
} else if ($scope.options.primary == 'primaryOption2') {
$scope.secondaryOptions = [
{value: 'bar', title: 'Bar'},
{value: 'baz', title: 'Baz'}]
}
$scope.options.secondary = $scope.secondaryOptions[0]
}
$scope.options.primary = 'primaryOption2'
updateAllowedSecondaryOptions()
$scope.primarySelected = function (newValue) {
$scope.options.primary = newValue;
updateAllowedSecondaryOptions()
}
};
http://jsfiddle.net/G5PLL/
You can see more about what is happening by reading https://github.com/angular/angular.js/wiki/Understanding-Scopes which goes into what is happening to detach you from the prototypal inheritance.
P.S. Misko's rule “Whenever you have ng-model there’s gotta be a dot in there somewhere. If you don’t have a dot, you’re doing it wrong.”