How to use Angular controller in Zeppelin - apache-zeppelin

I'm new to Zeppelin, recently I'm study how to use Zeppelin in my current project. I want to add a Angular controller in Zeppelin paragraph. But it's failed. Can you please give me some hints how to solve it? Below is my code.
println(s"""
%angular
<script>
angular.module('zeppelinWebApp').controller('myNewController', myNewController);
function myNewController() {
var vm = this;
vm.publicVariable = {};
// Controller's public functions
vm.myControllerPublicFunction = myControllerPublicFunction;
_init();
function myControllerPublicFunction() {
publicVariable = publicVariable + 1;
}
function _init() {
vm.myControllerPublicFunction();
}
}
</script>
<div ng-controller="myNewController as newCtrl">
<div ng-click="newCtrl.myControllerPublicFunction" ng-bind='newCtrl.publicVariable'></div>
</div>
""")

Been struggling with this myself. The best answer I've come up with is to create a pseudo-controller by grabbing a scoped element using jQuery (based off this GitHub gist):
println(s"""
%angular
<script>
var element = $('#ctrlHook');
var scope = angular.element(element.parent('.ng-scope')).scope().compiledScope;
(function myNewController() {
var vm = scope;
vm.publicVariable = 0;
// Controller's public functions
vm.myControllerPublicFunction = myControllerPublicFunction;
_init();
function myControllerPublicFunction() {
vm.publicVariable = vm.publicVariable + 1;
}
function _init() {
vm.myControllerPublicFunction();
}
})();
</script>
<div id="ctrlHook">
<div ng-click="myControllerPublicFunction" ng-bind='publicVariable'></div>
</div>
""")
You can of course remove the function block and just operate on scope directly instead of on vm, but I left it in to adhere to your original example as much as possible (I tidied up some variable references where you were calling publicVariable instead of vm.publicVariable and treating it like a number instead of the object it was initialised as).
NB: I cannot confirm whether the variable changes themselves would fix your original code, but I have tested grabbing the scope using the method above and it seems to work. Hope it helps you out.

Related

AngularJS how to declare private variable and function in controller

i wrote a small controller where i declare a variable with var keyword which is not in scope. does it means that is private in scope ? see my code.
<div ng-app="myApp" ng-controller="myCtrl">
{{test}}
</div>
var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
var test='test hello';
$scope.Operantion = 'hello';
$scope.GetData = function () {
abc();
};
function abc()
{
alert(test);
}
$scope.GetData();
});
the var test variable should be consider as private variable ?
if i declare a function with just function xxx() then it should be consider as private function. i am new in angular. so when testing code then many question is coming to my mind. so please guide me. thanks
Yes. var test and function xxx() should be considered "private" or, better, local data and function.
For reference see:
Angularjs scope
What is the scope of variables in javascript
Scope is an object, that the view can see and read values from it. By declaring a 'var', you are creating an object outside of the scope, but in the context of the controller function.
BUT the html, that comes with that controller via the ng-controller attribute for example, can only see properties of the scope of that controller.
import {Pipe, PipeTransform} from '#angular/core';
#Pipe({ name: 'reverse' })
export class ReversePipe implements PipeTransform {
transform(arg1) {
let data = '';
for (let i = 0; i < arg1.length; i++) {
data = arg1[i] + data;
}
return data;
}
}

Angular - Moving function into a service

I have a function that I'm now needing to use in multiple page so decided to move into a service - however its not going as I'm expecting.
So in my HTML i have:
<li ng-init="bg = underQBar(work.options)">
Then in the controller (before I moved the common function) it looked like:
$scope.underQBar = function(toWorkArray) {
//some implementation, with a return at the end
}
Now I've made my service:
function barService($window){
var self = this;
self.getBarColours = function(toWorkArray) {
//copied the implementation with the return here
}
}
And therefore trying this in my controller:
$scope.underQBar = barService.getBarColours(toWorkArray);
However this doesnt work, its not getting the parameter I'm sending from the HTML - is this a trivial fix or something wrong with the implementation?
This is the problem:
$scope.underQBar = barService.getBarColours(toWorkArray);
Here, you're assigning the result of the service function call to $scope.underQBar, when you meant to assign it the function itself.
This should work:
$scope.underQBar = barService.getBarColours;
If you want to make it more clear to the reader that it's a function, just do:
$scope.underQBar = function (toWorkArray) {
return barService.getBarColours(toWorkArray);
}
Here is a correct definition for your service :
angular.module("myModule").factory("BarService", ["$window", function($window){
var service = {};
service.getBarColours = function(toWorkArray){
//copied the implementation with the return here
};
return service;
}]);
And here is a correct way to inject the service in your controller :
angular.module("myModule").controller("controllerName", ["BarService", function(BarService){
var self = this;
self.getBarColours = BarService.getBarColours;
}]);
and here is the way to use it:
<li ng-init="bg = controllerName.underQBar(work.options)">
Explanation :
A service or a factory in angular cannot be accessed by your view. Your view can only make a call to your controllers.
If your function should have been called by many controllers, you can put this function in a global controller that will be responsible for controlling your whole view.

AngularJs - service does not update controller

I am trying to implement this simple Plunker with no success.
I have a simple service (factory) :
(function () {
'use strict';
angular
.module('app.core')
.factory('PropertiesService', PropertiesService);
function PropertiesService() {
var sefl = this;
self.name = 'Properties Service'
self.properties = {};
self.setProperties = function (prop)
{
self.properties = prop;
}
return self;
}
})();
I am calling this service from a directive :
var prop = { 'top': top, 'left': left, 'position': position };
service.setProperties(prop);
The contoller being updated is :
(function () {
'use strict';
angular
.module('app.properties')
.controller('Properties', Properties);
Properties.$inject = ['PropertiesService'];
function Properties(PropertiesService) {
var vm = this;
vm.collection = {};
setCollection();
function setCollection() {
for (var key in PropertiesService.properties) {
if (PropertiesService.properties.hasOwnProperty(key)) {
vm.collection[key] = PropertiesService.properties[key];
}
}
};
}
})();
Lastly , I am showing the data in html like this :
<div ng-controller="Properties as vm">
<ul class="list-group">
<li class="list-group-item" ng-repeat="(key, value) in vm.collection">
<span>{{key}}</span> : <span>{{value}}</span>
</li>
</ul>
</div>
I understand why i'm getting result only on initialization but I can not find the way to solve it,to make the controller updated when the service is changed (and it does) .
Thanks
Just to note something.
In your plunker you use a service and you try the same code with a factory. This cannot work. there are some differences between the two providers.
Either you use a factory:
function PropertiesFactory() {
// facory doens't get invoked with the new keyword
// so there is no this
var self = {};
self.name = 'Properties Factory'
self.properties = {};
self.setProperties = function (prop)
{
self.properties = prop;
}
return self;
}
or a service:
function PropertiesService() {
var sefl = this;
self.name = 'Properties Service'
self.properties = {};
self.setProperties = function (prop)
{
self.properties = prop;
}
// there is no need for return
// since th service gets invoked with the new keyword
}
form the angularjs docs about providers:
The Service recipe produces a service just like the Value or Factory
recipes, but it does so by invoking a constructor with the new
operator. The constructor can take zero or more arguments, which
represent dependencies needed by the instance of this type.
As it turn out i was hiding an important part of the code , not deliberately but from lack of understanding.
My directive is listening on DOM events and acting upon their changed data.
After reading this article (and help from my CTO...) I understood i needed to manually call $scope.$apply().
Now I have an element i can resize,drag etc. and have its changed properties eflect on the screen.
Now the binding is working again I can revert the controller code to look like this:
function Properties(PropertiesService) {
var vm = this;
vm.collection = PropertiesService.data;
}
Everything is in sync.
Sorry for the partial data , and thanks for the help.
Gilad

angularjs - use injected service to get properties

I'm writing a basic calculator app on jsfiddle to get some more experience with angular and I wanted to know if injected services can be used like objects to get properties. For example:
angular.module('CalcApp', [])
.controller('CalcVm', CalcVm)
.service('MathOperations', MathOperations);
angular.$inject = ['MathOperations'];
function CalcVm(MathOperations) {
var vm = this;
vm.xyz = '';
//code
}
function MathOperations() {
var addOp = '+';
var subtractOp = '-';
//etc..
}
is it possible to do this in the view:
<div ng-controller='CalcVm as calcVm'>
<button>{{calcVm.MathOperations.addOp}}</button>
</div>
should I bind the service to a variable in the controller?
function CalcVm(MathOperations) {
var vm = this;
vm.xyz = '';
vm.MathOperations = MathOperations;
//code
}
Ok so I've been experimenting with this and I've figured it out.
what worked was the following:
angular.module('CalcApp', [])
.controller('CalcVm', CalcVm)
.service('MathOperations', MathOperations);
angular.$inject = ['MathOperations'];
function CalcVm(MathOperations) {
var vm = this;
vm.MathOperations = MathOperations;
//more code
}
function MathOperations() {
this.addOp = '+';
this.subtractOp = '-';
//etc..
}
notice that I've used the keyword this in the service and I've assigned the injected service to a variable in my controller.
I'm not sure if this is good or bad practice and if anyone knows please edit this answer below the line with further info.

AngularJS access scope from outside js function

I'm trying to see if there's a simple way to access the internal scope of a controller through an external javascript function (completely irrelevant to the target controller)
I've seen on a couple of other questions here that
angular.element("#scope").scope();
would retrieve the scope from a DOM element, but my attempts are currently yielding no proper results.
Here's the jsfiddle: http://jsfiddle.net/sXkjc/5/
I'm currently going through a transition from plain JS to Angular. The main reason I'm trying to achieve this is to keep my original library code intact as much as possible; saving the need for me to add each function to the controller.
Any ideas on how I could go about achieving this? Comments on the above fiddle are also welcome.
You need to use $scope.$apply() if you want to make any changes to a scope value from outside the control of angularjs like a jquery/javascript event handler.
function change() {
alert("a");
var scope = angular.element($("#outer")).scope();
scope.$apply(function(){
scope.msg = 'Superhero';
})
}
Demo: Fiddle
It's been a while since I posted this question, but considering the views this still seems to get, here's another solution I've come upon during these last few months:
$scope.safeApply = function( fn ) {
var phase = this.$root.$$phase;
if(phase == '$apply' || phase == '$digest') {
if(fn) {
fn();
}
} else {
this.$apply(fn);
}
};
The above code basically creates a function called safeApply that calles the $apply function (as stated in Arun's answer) if and only Angular currently isn't going through the $digest stage. On the other hand, if Angular is currently digesting things, it will just execute the function as it is, since that will be enough to signal to Angular to make the changes.
Numerous errors occur when trying to use the $apply function while AngularJs is currently in its $digest stage. The safeApply code above is a safe wrapper to prevent such errors.
(note: I personally like to chuck in safeApply as a function of $rootScope for convenience purposes)
Example:
function change() {
alert("a");
var scope = angular.element($("#outer")).scope();
scope.safeApply(function(){
scope.msg = 'Superhero';
})
}
Demo: http://jsfiddle.net/sXkjc/227/
Another way to do that is:
var extScope;
var app = angular.module('myApp', []);
app.controller('myController',function($scope, $http){
extScope = $scope;
})
//below you do what you want to do with $scope as extScope
extScope.$apply(function(){
extScope.test = 'Hello world';
})
we can call it after loaded
http://jsfiddle.net/gentletech/s3qtv/3/
<div id="wrap" ng-controller="Ctrl">
{{message}}<br>
{{info}}
</div>
<a onClick="hi()">click me </a>
function Ctrl($scope) {
$scope.message = "hi robi";
$scope.updateMessage = function(_s){
$scope.message = _s;
};
}
function hi(){
var scope = angular.element(document.getElementById("wrap")).scope();
scope.$apply(function() {
scope.info = "nami";
scope.updateMessage("i am new fans like nami");
});
}
It's been a long time since I asked this question, but here's an answer that doesn't require jquery:
function change() {
var scope = angular.element(document.querySelector('#outside')).scope();
scope.$apply(function(){
scope.msg = 'Superhero';
})
}
Here's a reusable solution: http://jsfiddle.net/flobar/r28b0gmq/
function accessScope(node, func) {
var scope = angular.element(document.querySelector(node)).scope();
scope.$apply(func);
}
window.onload = function () {
accessScope('#outer', function (scope) {
// change any property inside the scope
scope.name = 'John';
scope.sname = 'Doe';
scope.msg = 'Superhero';
});
};
You can also try:
function change() {
var scope = angular.element( document.getElementById('outer') ).scope();
scope.$apply(function(){
scope.msg = 'Superhero';
})
}
The accepted answer is great. I wanted to look at what happens to the Angular scope in the context of ng-repeat. The thing is, Angular will create a sub-scope for each repeated item. When calling into a method defined on the original $scope, that retains its original value (due to javascript closure). However, the this refers the calling scope/object. This works out well, so long as you're clear on when $scope and this are the same and when they are different. hth
Here is a fiddle that illustrates the difference: https://jsfiddle.net/creitzel/oxsxjcyc/
I'm newbie, so sorry if is a bad practice. Based on the chosen answer, I did this function:
function x_apply(selector, variable, value) {
var scope = angular.element( $(selector) ).scope();
scope.$apply(function(){
scope[variable] = value;
});
}
I'm using it this way:
x_apply('#fileuploader', 'thereisfiles', true);
By the way, sorry for my english
<input type="text" class="form-control timepicker2" ng-model='programRow.StationAuxiliaryTime.ST88' />
accessing scope value
assume that programRow.StationAuxiliaryTime is an array of object
$('.timepicker2').on('click', function ()
{
var currentElement = $(this);
var scopeValues = angular.element(currentElement).scope();
var model = currentElement.attr('ng-model');
var stationNumber = model.split('.')[2];
var val = '';
if (model.indexOf("StationWaterTime") > 0) {
val = scopeValues.programRow.StationWaterTime[stationNumber];
}
else {
val = scopeValues.programRow.StationAuxiliaryTime[stationNumber];
}
currentElement.timepicker('setTime', val);
});
We need to use Angular Js built in function $apply to acsess scope variables or functions outside the controller function.
This can be done in two ways :
|*| Method 1 : Using Id :
<div id="nameNgsDivUid" ng-app="">
<a onclick="actNgsFnc()"> Activate Angular Scope</a><br><br>
{{ nameNgsVar }}
</div>
<script type="text/javascript">
var nameNgsDivVar = document.getElementById('nameNgsDivUid')
function actNgsFnc()
{
var scopeNgsVar = angular.element(nameNgsDivVar).scope();
scopeNgsVar.$apply(function()
{
scopeNgsVar.nameNgsVar = "Tst Txt";
})
}
</script>
|*| Method 2 : Using init of ng-controller :
<div ng-app="nameNgsApp" ng-controller="nameNgsCtl">
<a onclick="actNgsFnc()"> Activate Angular Scope</a><br><br>
{{ nameNgsVar }}
</div>
<script type="text/javascript">
var scopeNgsVar;
var nameNgsAppVar=angular.module("nameNgsApp",[])
nameNgsAppVar.controller("nameNgsCtl",function($scope)
{
scopeNgsVar=$scope;
})
function actNgsFnc()
{
scopeNgsVar.$apply(function()
{
scopeNgsVar.nameNgsVar = "Tst Txt";
})
}
</script>
This is how I did for my CRUDManager class initialized in Angular controller, which later passed over to jQuery button-click event defined outside the controller:
In Angular Controller:
// Note that I can even pass over the $scope to my CRUDManager's constructor.
var crudManager = new CRUDManager($scope, contextData, opMode);
crudManager.initialize()
.then(() => {
crudManager.dataBind();
$scope.crudManager = crudManager;
$scope.$apply();
})
.catch(error => {
alert(error);
});
In jQuery Save button click event outside the controller:
$(document).on("click", "#ElementWithNgControllerDefined #btnSave", function () {
var ngScope = angular.element($("#ElementWithNgControllerDefined")).scope();
var crudManager = ngScope.crudManager;
crudManager.saveData()
.then(finalData => {
alert("Successfully saved!");
})
.catch(error => {
alert("Failed to save.");
});
});
This is particularly important and useful when your jQuery events need to be placed OUTSIDE OF CONTROLLER in order to prevent it from firing twice.

Resources