AngularJs controller add all html elements from template - javascript

I want to add all my elements from my template to my $scope.
I want them to be accessible like c# or java elements in the code.
for example
if i have this HTML template
<div ch-options-div id="chOptions" ng-controller="chOptionsCtrl">
<span>Options</span>
<div id="chOptionsWrapper">
<div id="div1">
</div>
<div id="div2"></div>
<div id="div3"></div>
</div>
</div>
And here is a possible controller:
var chOptions = angular.module('chOptions',[]);
chOptions.controller('chOptionsCtrl', function ($scope,$document,$element)
{
//select all elements by id and add them to scope
$scope.chOptionsWrapper = document.getElementById('chOptionsWrapper');
//or with jquery
$scope.div1 = $('#div1')
}
Is there a best case to do this or is there a good way to add all my HTML elements to the scope ? I want clean "object oriented" javascript code.

You can use a directive to achieve this.
.directive('box', function () {
return {
scope: {
rgb: '='
},
link: function (scope, elem, attrs) {
scope.$watch('rgb', function () {
angular.element(elem).css('background-color', 'rgb(' + scope.rgb + ')');
});
}
}
}
Here is an example of you to use the directive: http://jsfiddle.net/skriblez/dqfwvyso/4/

Related

Why can`t I access scope via controller?

I am working on passion project. And I cant access scope to pass data to back-end frame work.
Here is my index file
<div id="main-menu" ng-controller="appCtrl">
//some other code
<div id="includedDocumentsFilter" style="float:right; display:none; padding-right: 10px;">
<my-documents validate-options="validateDialogOptions()" call-dialog="showDialog()"> </my-documents>
</div>
//some other code
</div>
My custom directive
'use strict';
dbApp
.directive('myDocuments', [
function () {
var documentTemplate =
' <div class="caption-row">' +
'<kendo-button style="width:62px" ng-click="changeDocument(true)"> Ok </kendo-button>'+
'<kendo-button style="width:62px" ng-click="changeDocument(false)" > Revert changes </kendo-button>'+
'</div>'
}
return {
scope: true,
template: documentTemplate
}
}]
)
My controller
$scope.changeDocument = function (applyFilter) {
if (applyFilter === true) {
//Here is where I cant access $scope
}
}
Firstly, I see a extra closing curly braces in your directive. Secondly in your html code there is display:none in div with id "includedDocumentsFilter". Just wondering if you are hiding the div, how will you be able to see the template defined in your directive. I have added a working jsfiddle link below using your above mentioned code
dbApp.directive('myDocuments', [
function () {
var documentTemplate =
' <div class="caption-row">' +
'<kendo-button style="width:62px" ng-click="changeDocument(true)"> Ok </kendo-button>'+
'<kendo-button style="width:62px" ng-click="changeDocument(false)" > Revert changes </kendo-button>'+
'</div>'
return {
scope: true,
template: documentTemplate
}
}]
)
JsFiddle link: https://jsfiddle.net/anilsarkar/gk2dfh1p/21/
Note: I have replaced kendo-button with span in jsfiddle

Error: [$compile:nonassign] Expression 'undefined' in attribute [ATTRIBUTENAME] used with directive '[DIRECTIVENAME]' is non-assignable?

When I'm trying to transform date inside the directive's body I get error:
Error: [$compile:nonassign] Expression 'undefined' in attribute
[ATTRIBUTENAME] used with directive '[DIRECTIVENAME]' is
non-assignable!
I am using angular version 1.4.14
Expected result: in my template directive will return class name -
div class="news-block-container sm-padding-right"
What can cause this problem? Thanks for your answer
here is an example of my code:
'use strict';
angular.module('test.directives')
.directive('test', function () {
var templatePath = "/views/templates/testTemplate.tmpl.html";
return {
restrict: 'E',
scope: {
position: '=',
},
templateUrl: templatePath,
link: function (scope, element, attrs) {
scope.$watch('position', function () {
if (scope.position === "left") {
scope.position = "sm-padding-right";
}
else {
scope.position = "sm-padding-left";
}
});
}
}
});
view - directive usage
<test-template position="'left'"></test-template>
//!TEMPLATE! - testTemplate
<div>
<a href="{{#}}">
<div class="news-block-container {{position}}">
</div>
</a>
</div>
Just use ng-class directive to assign class dynamically
<div>
<a href="{{#}}">
<div class="news-block-container" ng-class="position">
</div>
</a>
</div>
change angular.module('test.directives')
to this angular.module('test.directives',[])
Also remove the curly brackets around hash in template
change <a href="{{#}}">
to this <a href="#">

Pass json value as ng-model value in angular 1.2

I'm trying to bind 2 separate elements so that one can trigger the other. The first step in this, is adding an identifying variable to my component template.
Here's the bullet.html template:
<div class="button bullet" ng-model="component.bullet.show_on_click" ng-click="showElementByUniqueName( component.bullet.show_on_click )"><p>{{component.bullet.text}}</p></div>
I'd like to know what is the correct syntax to set ng-model as the VALUE in component.bullet.show_on_click. At the moment, in the final html, ng-model turns out just as shown in the template. I have tried single speech marks and single AND double curly braces; All throw errors.
Any help, much appreciated!
EDIT
On request, here is some more detail:
The eng-bullet attribute fires up the engBullet directive:
app.directive('engBullet', function() {
return {
restrict: 'A',
replace: true,
templateUrl: 'components/bullet.html',
link: function(scope, element, attrs) {
// following function referenced in bullet.html
scope.showElementByUniqueName = function (showOnClick) {
// remove 'replaces' element
$('#'+$('#'+showOnClick).attr('data-replaces')).addClass('hidden');
// hide all popups (in case another popup is currently visible)
$('.popup').addClass("hidden");
// show selected popup
$('#'+showOnClick).removeClass("hidden");
}
}
};
});
The eng-popup attribute fires up the engPopup directive:
app.directive('engPopup', function() {
return {
restrict: 'A',
replace: true,
templateUrl: 'components/popup.html',
link: function(scope, element, attrs) {
scope.show = true;
scope.complete = false;
// watch for this popup being made visible and check if
scope.$watch(function() { return element.is(':visible') }, function() {
scope.$parent.componentCompleted(attrs.id);
});
}
};
});
..which loads in the components/popup.html template:
<div class="hidden popup {{component.popup.type}}" id="{{component.popup.name}}" data-replaces="{{component.popup.replaces}}" eng-completable ng-show="component.popup.name">
<div ng-if="component.popup.type=='overlay'">
<div class="float-right button close-button">X</div>
</div>
<p class="heading">{{component.popup.heading}}</p>
<div class="popup-content">
<div ng-if="0" ng-repeat-start="(innerIndex, component) in component.popup.popup_components"></div>
<div ng-if="0" ng-repeat-start="(type, object) in component"></div>
<div ng-attr-id="{{'p' + pageId + '-s' + skey + '-c' + ckey + '-component-' + index + '-innerComponent-' + innerIndex}}" ng-switch="type">
<div ng-switch-when="image" eng-image></div>
<div ng-switch-when="paragraph" eng-paragraph></div>
</div>
<div ng-if="0" ng-repeat-end></div>
<div ng-if="0" ng-repeat-end></div>
</div>
</div>
I'm not sure this is really relevant to the question though, which is how do I get the VALUE in component.bullet.show_on_click to present in the final html as the value of ng-model in the bullet html template, eg:
ng-model="unique_name_here"
?
Thanks.

Pass scope variable from directive to it's controller

This is possibly easy, but I have browsed the different questions here on SO and in the Angular documentation and can't really find what I'm looking for.
In a directive:
function ssKendoGrid() {
return {
scope: {
dataSource: "="
},
template: "<div kendo-grid k-options='gridOptions'></div>",
controller: "ssKendoGridCtrl",
}
}
That uses the controller:
function ssKendoGridCtrl($scope) {
alert($scope.dataSource);
//other stuff
}
If I want to access the value of dataSource I assumed I'd be able to do something like this:
<div ng-controller="myController">
<div ss-kendo-grid data-source="test"></div>
</div>
MyController is:
function myController($scope) {
$scope.test = "Tested";
}
But it comes as undefined when I try to alert($scope.dataSource); the value..
Now I know I can do this:
<div ss-kendo-grid="test"></div>
And access it in the directive and controller like this:
return {
scope: {
ssKendoGrid: "="
},
template: "<div kendo-grid k-options='gridOptions'></div>",
controller: "ssKendoGridCtrl"
}
//In controller
alert($scope.ssKendoGrid);
But I would like to be able to pass in a JSON object to do various things with and this doesn't seem as clean as in the markup I'd like it to be more intuitive to look at the html and know what the dataSource is.
What I'm really looking for is an understanding of what I'm doing wrong, why doesn't this work?? I've obviously not got the right understanding of how to pass various things to the isolated scope of the directive.
SOLVED
So, turns out I was using the wrong attribute name. HTML5 recognizes data- as a valid attribute, and Angular ignores the fact that data- is prefixed on the variable, which means that I would need to access the variable this way:
HTML:
<div ss-kendo-grid data-source="test"></div>
JS:
return {
scope: {
dataSource: "=source"
},
template: "<div kendo-grid k-options='gridOptions'></div>",
controller: "ssKendoGridCtrl"
}
Cheers
you need to access the directive scope variable as
<div ss-kendo-grid data-source="test"></div>
similarly as you name the directive in the HTML markup
So, turns out I was using the wrong attribute name. HTML5 recognizes data- as a valid attribute, and Angular ignores the fact that data- is prefixed on the variable, which means that I would need to access the variable this way:
HTML:
<div ss-kendo-grid data-source="test"></div>
JS:
return {
scope: {
dataSource: "=source"
},
template: "<div kendo-grid k-options='gridOptions'></div>",
controller: "ssKendoGridCtrl"
}
And a better convention is to simply not use a directive with "data-" at the beginning of it.
invite.directive('googlePlaces', function (){
return {
restrict:'E',
replace:true,
// transclude:true,
scope: {location:'=location'},
template: '<input id="google_places_ac" name="google_places_ac" type="text" class="input-block-level"/>',
link: function(scope, elm, attrs){
var autocomplete = new google.maps.places.Autocomplete($("#google_places_ac")[0], {});
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
scope.location = place.geometry.location.lat() + ',' + place.geometry.location.lng();
console.log(scope.location);
scope.$apply();
// scope.$apply(function() {
// scope.location = location;
// });
});
}
};
});

AngularJS The scope for dynamic content through $compile isn't attached to the controller scope

When I generate a new element through a string that has a directive (that's why I need to compile) and that directive generates an association with a variable in the controller scope through "=", the variable in my controller isn't associated to the one in the directive.
I created a jsfiddle to show the example where the "door" ng-model value should be associated to all the directives model values.
See this fiddle: http://jsfiddle.net/aVJqU/2/
Another thing I notice is that the directive that run from elements present in the html show the correct association through the variables (controller and directive).
The html (there is the directive that binds <door>):
<body ng-app="animateApp">
<div ng-controller="tst">
<h2> Controller with its model </h2>
<input ng-model="doorval" type="text"> </input>
{{doorval}}
<h2> Directive render directly from the html </h2>
<door doorvalue="doorval"></door> <key></key>
<h2> Directives that are compiled </h2>
<list-actions actions="actions"></list-actions>
</div>
</body>
This is the directive:
animateAppModule.directive('door', function () {
return {
restrict: "E",
scope: {
doorvalue:"="
},
template: '<span>Open the door <input type="text" ng-model="doorvalue"> </input> {{doorvalue}}</span>',
replace: true
}
})
This is the controller:
var animateAppModule = angular.module('animateApp', [])
animateAppModule.controller('tst', function ($scope, tmplService) {
$scope.doorval = "open"
$scope.actions = tmplService;
})
animateAppModule.service('tmplService', function () {
return [{
form_layout: '<door doorvalue="doorval"></door> <key></key>'
}, {
form_layout: '<door doorvalue="doorval"></door> with this <key></key>'
}]
})
And finally this is the directive that compiles the string that has the directive that doesn't bind:
animateAppModule.directive('listActions', function ($compile) {
return {
restrict: "E",
replace: true,
template: '<ul></ul>',
scope: {
actions: '='
},
link: function (scope, iElement, iAttrs) {
scope.$watch('actions', function (neww, old,scope) {
var _actions = scope.actions;
for (var i = 0; i < _actions.length; i++) {
//iElement.append('<li>'+ _actions[i].form_layout + '</li>');
//$compile(iElement.contents())(scope)
iElement.append($compile('<li>' + _actions[i].form_layout + '</li>')(scope))
}
})
}
}
})
What can I do to bind all the "door" ng-model values together?
Where is the compiled directive binding to?
You just have to pass the doorval reference down through all directives without skip any one. The problem was the listActions directive didn't had access to doorval in its scope.
Check this out: http://jsfiddle.net/aVJqU/5/
#Danypype is basically correct as the problem occurs due to scope isolation, as explained in the documentation.
An alternative solution is to simply eliminate the scope isolation by removing the scope block from within the directive definition.

Categories

Resources