I am creating a basic page that shows and lets you edit/add/remove children of a tree. I've made a recursive directive to print them out, but I am really confused on how should I be going about removing an array element, as I need to know its parent to call splice.
Any help really appreciated, been scratching my head for hours now :/
Should I be passing the parent element down as an attribute?
app.controller('treeController', ['$scope', function($scope)
{
//Root object
$scope.tree = {
name : "Root",
expand : true,
children : []
};
//Temp data filler.
$scope.fillData = function()
{
var child1 = {
name : "Element 1",
expand : false,
children : []
};
var child2 = {
name : "Element 2",
expand : false,
children : []
};
var subChild1 = {
name : "Child 1",
expand : false,
children : []
};
var subChild2 = {
name : "Child 2",
expand : false,
children : []
};
var grandChild1 = {
name : "grandChild 1",
expand : false,
children : []
};
var grandChild2 = {
name : "grandChild 2",
expand : false,
children : []
};
// Add the children
$scope.tree.children.push(child1);
$scope.tree.children.push(child2);
$scope.tree.children[0].children.push(subChild1);
$scope.tree.children[1].children.push(subChild1);
$scope.tree.children[0].children.push(subChild2);
$scope.tree.children[1].children.push(subChild2);
$scope.tree.children[0].children[0].children.push(grandChild1);
$scope.tree.children[0].children[1].children.push(grandChild1);
$scope.tree.children[1].children[0].children.push(grandChild1);
$scope.tree.children[1].children[1].children.push(grandChild1);
$scope.tree.children[0].children[0].children.push(grandChild2);
$scope.tree.children[0].children[1].children.push(grandChild2);
$scope.tree.children[1].children[0].children.push(grandChild2);
$scope.tree.children[1].children[1].children.push(grandChild2);
}
}]);
app.directive('collection', function () {
return {
restrict: "E",
replace: true,
scope: {
collection: '='
},
template: "<ul><member ng-repeat='member in collection.children' member='member'></member></ul>"
}
})
app.directive('member', function ($compile) {
return {
restrict: "E",
replace: true,
scope: {
member: '='
},
//template: "<li></li>",
templateUrl: 'node.html',
link: function (scope, element, attrs) {
var collectionSt = '<collection collection="member"></collection>';
//check if this member has children
if (angular.isArray(scope.member.children))
{
$compile(collectionSt)(scope,
function(cloned, scope)
{
element.append(cloned);
});
}
scope.deleteMe = function(index)
{
//var index = array.indexOf(member);
alert(array.indexOf($scope.member))
};
}
}
});
Related
I created a filter for a list of scholarships and it was working fine using the code below, but now I realize that I need to be able to display a particular scholarship when either "Freshmen" or "Sophomores" is selected from the "Standing" dropdown—but I can't figure out how to include multiple standings per scholarship.
Is it possible to accomplish this with an adjustment to the code below, or have I set myself up for failure?
var filters = {
need: "",
standing: "",
};
need.value = filters.need;
standing.value = filters.standing;
need.addEventListener("input", function() {
filters.need = need.value;
update();
});
standing.addEventListener("input", function() {
filters.standing = standing.value;
update();
});
function filterNeed(scholarship) {
return !filters.need.length || scholarship.need == filters.need;
}
function filterStanding(scholarship) {
return !filters.standing.length || scholarship.standing == filters.standing;
}
function update() {
let filteredCards = getScholarships().filter(filterNeed).filter(filterStanding);
console.log(filters);
output.innerHTML = filteredCards.map(scholarship => `<span>${scholarship.name}</span>`).join("");
};
update();
function getScholarships() {
return [
{
name: "Scholarship 1",
link: "#",
need: "yes",
standing: "Freshmen",
},
{
name: "Scholarship 2",
link: "#",
need: "no",
standing: "Sophomore",
},
{
name: "Scholarship 3",
link: "#",
need: "yes",
standing: "Junior",
}
];
}
Use arrays:
...
standing: ["Junior", "Sophomore"],
and fix filterStanding:
function filterStanding(scholarship) {
return !filters.standing.length || scholarship.standing.some(v => v == filters.standing);
}
I have an angular directive with a scope.$watch which is not working, but I know the value is changing. Here's the directive:
var StepFormDirective = function ($timeout, $sce, dataFactory) {
return {
replace: false,
restrict: 'AE',
scope: {
currentStep: "=",
title: "="
},
template: '<h3>{{title}}</h3><form class="step-form"></form>',
compile: function (tElem, attrs) {
return function (scope, elem, attrs) {
scope
.$watch(
function(){return scope.currentStep;},
function (newValue) {
var stepFormFields = Array();
stepFormFields.push($sce.trustAsHtml("<p>Fields</p>"));
alert(scope.currentStep);
}
);
};
}
};
};
Here's the tag:
<div title="'test'" currentStep="currentContext.currentStep"></div>
I know the currentContext.currentStep is changing, because I also have this on my page and it updates:
<pre>{{currentContext.currentStep | json}}</pre>
The alert gets called the first time, but then when the value changes (evidenced by the bit in the pre tags) the alert does not get called again and I have no js console errors.
The output for the step (it's data type) is:
{
"identifier": "830abacc-5f88-4f9a-a368-d8184adae70d",
"name": "Test 1",
"action": {
"name": "Approval",
"description": "Approve",
"instructions": "Select 'Approved' or 'Denied'",
"validOutcomes": [
{
"outcome": "Approved",
"display": "Approved",
"id": "Approved"
},
{
"outcome": "Denied",
"display": "Denied",
"id": "Denied"
}
]
...
Try to use $watch method with third argument set by true (objectEquality):
$watch('currentStep', function(newValue){...}, true);
Or use $watchCollection:
$watchCollection('currentStep', function(newValue){...})
Having a problem with nested directives and inheriting the scope from a parent. It happens that the scope I want to inherit from is an isolated scope. I've the code below
test.html
<div ng-controller="testCtrl as test">
<special-select data-selected-item="test.selectedThing">
<special-select-selected-item></special-select-selected-item>
</special-select>
</div>
app.js
angular
.module('testApp', ['special-inputs'])
.controller('testCtrl', [
function() {
this.items = [
{ id: 1, name: 'alex 1', displayName:"alex 1 dn", imageUrl: 'http://placehold.it/505x100' }
];
this.selectedThing = this.items[0];
this.test = function() {
console.log('test fn');
}
}
]);
special-inputs.js
angular
.module('special-inputs', [])
.directive('specialSelect', [
function() {
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<div class="container" ng-transclude></div>',
scope: {
selectedItem: '='
},
link: {
pre: function(scope) {
console.log('parent link pre - ', scope.selectedItem);
},
post: function(scope) {
console.log('parent link post - ', scope.selectedItem);
}
}
}
}
])
.directive('specialSelectSelectedItem', [
function() {
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<div class="selected" ng-transclude></div>',
scope: true,
link: {
pre: function(scope) {
console.log('child link pre - ', scope.selectedItem);
},
post: function(scope) {
console.log('child link post - ', scope.selectedItem);
}
}
}
}
])
As you can see the nested directive is trying to create it's own isolate scope but grab the "selectedItem" from the isolate scope of the parent.
The docs say it should inherit and transclusion is semi prototypical, so I'm wondering why it's not working. Thanks. Any help would be appreciated
UPDATE
I've updated the code to show the problem I'm having now. It seems that the scope item is set in the pre + post link functions on the parent, but never get put down to the child. The console outputs
2015-12-29 15:13:44.258 special-select.js:35 parent link pre - Object {id: 1, name: "alex 1", displayName: "alex 1 dn", imageUrl: "http://placehold.it/505x100"}
2015-12-29 15:13:44.258 special-select.js:64 child link pre - undefined
2015-12-29 15:13:44.260 special-select.js:67 child link post - undefined
2015-12-29 15:13:44.260 special-select.js:38 parent link post - Object {id: 1, name: "alex 1", displayName: "alex 1 dn", imageUrl: "http://placehold.it/505x100"}
I've tried using scope.$watch and attrs.$observe to populate the valu
Hi I have a directive like,
mainApp.directive('myMenu',function(){
return {
restrict : 'E',
scope :{menuItems : "=menuItems"},
compile: function(element, attributes) {
var linkFunction = function($scope, element, attributes){
for (i = 0;i<$scope.menuItems.length;i++){
element.append('<li>'+$scope.menuItems[i].name+'</li>');
}
}
return linkFunction;
}
}
});
I am using it like below in my HTML
<my-menu menuItems="menuItems"></my-menu>
But in the console I am getting an error like
TypeError: Cannot read property 'length' of undefined
The problem could be that, then the linking phase is executed the menuitems may not be loaded so $scope.menuItems may be undefined.
A better solution could be
var mainApp = angular.module('my-app', [], function() {})
mainApp.controller('AppController', function($scope) {
$scope.menuItems = [{
name: 'one'
}, {
name: 'two'
}, {
name: 'three'
}, {
name: 'four'
}];
})
mainApp.directive('myMenu', function() {
return {
restrict: 'E',
scope: {
menuItems: "="
},
template: '<ul><li ng-repeat="item in menuItems">{{item.name}}</li></ul>'
}
});
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
<div ng-app="my-app" ng-controller="AppController">
<my-menu menu-items="menuItems"></my-menu>
</div>
If you can't use template then
var mainApp = angular.module('my-app', [], function() {})
mainApp.controller('AppController', function($scope) {
$scope.menuItems = [{
name: 'one'
}, {
name: 'two'
}, {
name: 'three'
}, {
name: 'four'
}];
})
mainApp.directive('myMenu', function() {
return {
restrict: 'E',
scope: {
menuItems: "=menuItems"
},
link: function($scope, element, attributes) {
$scope.$watch('menuItems', function(value) {
element.empty();
angular.forEach(value, function(item) {
element.append('<li>' + item.name + '</li>');
});
});
}
}
});
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
<div ng-app="my-app" ng-controller="AppController">
<my-menu menu-items="menuItems"></my-menu>
</div>
The Issue was with the name I used, like menuItems in directive should be equal to menu-items, solved the issue by repalcing the menuItems to menu.
use $scope.$eval(attributes.menuItems) inside compile function to get menuItems
In a controller I have defined two different arrays and I need to pass different arrays to directives, but the same item array is getting passed only.
Actually this is just snippets. In my actual code this directive I am using inside another.
Is that causing problem or any other way?
<div my-sticky tags="items" template_name="test2.html"></div>
<div my-sticky tags="kititems" template_name="test2.html"></div>
JS:
app.controller('MyCtrl', function($scope, $http) {
$scope.items = [
{ id: 18, text: '1' },
{ id: 28, text: '2' },
{ id: 38, text: '3' }
];
$scope.kititems = [
{ id: 0, text: '001' },
{ id: 028, text: '002' },
{ id: 038, text: '003' }
];
});
app.directive("mySticky", function($http, $compile) {
return {
restrict : "A",
scope : {
templateName: "#",
tags: "=",
},
templateUrl : function(el, attrs) {
return attrs.templateName;
},
controller : function($http, $scope, $element, $sce, $templateCache, $compile, $attrs) {
$scope.drawerStyle = {left: '140px'};
//$scope.CommonArray=$attrs.tags;
},
replace : false,
transclude : false,
link : function(scope, element, attrs) {
// change element just to show we can
}
};
});
Try this one
Working Demo
Inside your templateURL(test2.html) should like this i.e,
<div ng-repeat="tag in tags"> {{tag.id}} {{tag.text}} </div>
You might try to access items or kititems both are not in current scope because you have used isolated scope here.For clarity template used here instead of templateURL.
HTML Markup:
<div ng-controller="MyCtrl">
MyCtrl
<div my-sticky tags="items"></div>
<hr/>
<div my-sticky tags="kititems"></div>
</div>
angular modules
var app = angular.module("myApp",[]);
app.controller('MyCtrl', function($scope) {
$scope.items = [
{ id: 18, text: '1' },
{ id: 28, text: '2' },
{ id: 38, text: '3' }
];
$scope.kititems = [
{ id: 0, text: '001' },
{ id: 028, text: '002' },
{ id: 038, text: '003' }
];
});
app.directive("mySticky", function($http, $compile) {
return {
restrict : "A",
scope : {
templateName: "#",
tags: "=",
},
template :'<div ng-repeat="tag in tags"> {{tag.id}} {{tag.text}} </div>',
controller : function($http, $scope, $element, $sce, $templateCache, $compile, $attrs) {
$scope.drawerStyle = {left: '140px'};
// console.log($scope);
//$scope.CommonArray=$attrs.tags;
},
replace : false,
transclude : false,
link : function(scope, element, attrs) {
// change element just to show we can
}
};
});