Configure and access AngularJS $scope by a third party application - javascript

I'm developing an AngularJS application and I would like to integrate some functions to let an other web-application interact with the application. My application should run and triggered on the same website. Iframes are not used.
The application has several tabs, and I would like to set a tab active by specifying it's id.
This has been done in an AngularJS controller, through this method:
$scope.setActiveTab = function(tabId) {
ribbon.setActiveTab(tabId);
$scope.$apply();
}
In my application, I have a ng-click attribute and this function is being called in it. But now, I do want a other application to set the active tab by calling some JavaScript function.
Therefore, I've written the following function:
$.fn.OfficeUI.EnableTab = function(element) {
angular.element($('#OfficeUI')).scope().setActiveTab('tabSendReceive');
}
However, this doesn't work, but when I past this method:
angular.element($('#OfficeUI')).scope().setActiveTab('tabSendReceive');
in the developer console of FireBug or Google Chrome, then it's working.
Any idea on what's wrong and how I should solve this?
Kind regards

As I understand you right. You need a application which allows developers (as you said Users :) to interact and configure your application by using HTML/JavaScript. Checkout this plunker demo.
A good approach is to do this with configuration files, global object, or events bindings. The following example shows you, how to let a user configure an a global config object in JavaScript & allows developers to interact with your application. For example by using $scopes.
Controller with global configuration object:
/**
* Active state holder
* #type {null|integer}
*/
var myConfig = {
menus : {
mainbar: {
active: true
},
subbar: {
active: false
},
othersubbar: {
active: false
}
}
};
var OfficeUIRibbon = angular.module('OfficeUIRibbon', [])
OfficeUIRibbon.factory('OfficeUIRibbonFactory', [function() {
return {
setActiveTabId: function (tabId) {
activeTabId = tabId;
}
}
}]);
OfficeUIRibbon.controller('OfficeUIRibbon', ['$scope', '$http', '$animate', function($scope, $http, $animate) {
//as scope set
$scope.isVisible = function (name){
if (myConfig.menus[name].active) {
return 'active';
}
}
$scope.activateMenu = function (name) {
console.log(name);
if (!myConfig.menus[name].active) {
myConfig.menus[name].active = true;
}
}
$scope.deactivateMenu = function (name) {
if (myConfig.menus[name].active) {
myConfig.menus[name].active = false;
}
}
$scope.listing = {
mainbar: {
id: 1,
label: 'mainbar'
},
subbar: {
id: 2,
label: 'subbar'
},
othersubbar: {
id: 3,
label: 'othersubbar'
}
}
}]);
HTML-Template:
<head>
<link rel="stylesheet" href="style.css">
<script src="https://code.angularjs.org/1.3.10/angular.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="OfficeUIRibbon">
<ul>
<li ng-repeat="(key,list) in listing" ng-class="isVisible(key)">
{{ list.label }}
</li>
</ul>
<button ng-click="activateMenu('mainbar');">Activate Mainmenu</button>
<button ng-click="deactivateMenu('mainbar');">Deactivate Mainmenu</button>
</body>
</html>
User configuration, should be set before angular was loaded. For example, disable mainbar on default:
myConfig.menus.mainbar.active = false;

Please see demo below that should helps you.
var app = angular.module('app', []);
app.controller('firstCtrl', function($scope) {
$scope.test = function(msg) {
$scope.$apply(function() {
$scope.msg = msg
})
}
});
$(function() {
angular.element(document.querySelector('#contoller')).scope().test("Message for Angular from jQuery");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<div id="contoller" ng-controller="firstCtrl">
{{msg}}
</div>
</body>

try:-
$scope.apply(function(){
angular.element($('#OfficeUI')).scope().setActiveTab('tabSendReceive');
})
You are in jquery scope you must have to use $scope.apply to reflect it to angular.

Related

Unable to bind some data between components?

I am computing/building a javascript object in a directive (component) and I want to pass it to another component.
In my case, I am referring to the list of heroes that that is in the heroList.js (which is the source component), and I want to transfer the passingObject to the someOtherTabPage.js (which is the destination component).
This is the link to my plunk. Can you please help with this problem, I don't what's wrong in binding the passingObject to between my two components?
(function(angular) {
'use strict';
function someOtherTabPageController($scope) {
//do some work with the passingObject
alert(JSON.stringify(passingObject));
}
angular.module('heroApp').component('someOtherTabPage', {
templateUrl: 'someOtherTabPage.html',
controller: someOtherTabPageController,
bindings :{
passingObject: '='
}
});
})(window.angular);
To achieve what you need with the same architecture you can use the $rootScope to pass the data between your controllers. Here is the updated code :
(function(angular) {
'use strict';
function someOtherTabPageController($scope,$rootScope) {
var ctrl = this;
//do some work with the passingObject
alert($rootScope.passingObject);
}
angular.module('heroApp').component('someOtherTabPage', {
templateUrl: 'someOtherTabPage.html',
controller: someOtherTabPageController,
bindings :{
passingObject: '='
}
});
})(window.angular);
(function(angular) {
'use strict';
function HeroListController($scope, $element, $attrs,$rootScope) {
var ctrl = this;
// This would be loaded by $http etc.
ctrl.list = [
{
name: 'Superman',
location: ''
},
{
name: 'Batman',
location: 'Wayne Manor'
}
];
ctrl.create = function(hero) {
ctrl.list.push(angular.copy(hero));
};
ctrl.updateHero = function(hero, prop, value) {
hero[prop] = value;
};
ctrl.deleteHero = function(hero) {
var idx = ctrl.list.indexOf(hero);
if (idx >= 0) {
ctrl.list.splice(idx, 1);
}
};
$scope.passingObject = ctrl.list;
$rootScope.passingObject = ctrl.list;
}
angular.module('heroApp').component('heroList', {
templateUrl: 'heroList.html',
controller: HeroListController,
bindings: {
onCreate: '&'
}
});
})(window.angular);
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-heroComponentTree-production</title>
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script src="index.js"></script>
<script src="heroList.js"></script>
<script src="heroDetail.js"></script>
<script src="editableField.js"></script>
<script src="someOtherTabPage.js"></script>
</head>
<body ng-app="heroApp">
<hero-list></hero-list>
<some-other-tab-page></some-other-tab-page>
</body>
</html>
I think the way you're meant to grab the passingObject in the controller, after it has been bound by the component is via the this keyword
function someOtherTabPageController($scope) {
var ctrl = this;
//do some work with the passingObject
alert(JSON.stringify(ctrl.passingObject));
}
You can see the same principle applied in your example plunk in heroDetail.js in the HeroDetailController
EDIT to address last comment: 'passingObject is undefined'
My first guess would be that the component wasn't passed the passingObject in the instantiation. The right way would look like this:
<some-other-tab-page passing-object="someObjectHere"></some-other-tab-page>

Angular $scope is not available in the HTML Template but I can see it in console log?

I have been following some online tutorials and using the angularjs-template to get started with Angular. I can't get the page (html template) to update with the controller. I think there is a problem with the way I have set up the controller as the values are not available to the html template.
I have been trying to follow some of the best practive guides which suggested to wrap my components in an 'Invoked Function Expression' and to seperate out the controller, service and service manager. However, I think I have made a bit of a hash of this and need some help to figure out what I am doing wrong.
With the console I can see that $scope.metric contains the information I want. For me this means that the controller has successfully pulled the data back from my API via the metricService. However I can't seem to have the results printed back onto the html page e.g. metric.id.
Any help appreciated - I am at the end of my wits trying to figure this out.
metric.html
<div class="panel panel-primary">
<div class="panel-body">
<!-- Try First Way to Print Results -->
Id: <span ng-bind="metric.id"></span></br>
Name:<input type="text" ng-model="metric.metadata.name" /></br>
<!-- Try Second Way to Print Results -->
<p data-ng-repeat="thing in ::MEC.metric track by $index">
{{$index + 1}}. <span>{{thing.metadata.name}}</span>
<span class="glyphicon glyphicon-info-sign"></span>
</a>
</p>
<!-- Try Third Way to Print Results -->
Id: <span ng-bind="Metric.metricId"></span></br>
Id: <span ng-bind="Metric.id"></span></br>
Id: <span ng-bind="metricService.id"></span></br>
<!-- Try Fourth Way to Print Results -->
Id: <strong>{{::MEC.metric.id}}</strong></br>
Name: <strong>{{::MEC.metric.metadata.name}}</strong></br>
Height: <strong>{{::MEC.metric.type}}</strong>
</div>
metricController.js
(function () {
'use strict';
angular.module('app.metric', ['app.metricService', 'app.metricManager'])
.controller('MetricController', MetricController)
MetricController.$inject = ['$scope', 'metricManager', '$log'];
function MetricController($scope, metricManager, $log) {
metricManager.getMetric(0).then(function(metric) {
$scope.metric = metric
$log.info('$scope.metric printed to console below:');
$log.info($scope.metric);
})
}
})();
metricService.js
(function () {
'use strict';
angular.module('app.metricService', [])
.factory('Metric', ['$http', '$log', function($http, $log) {
function Metric(metricData) {
if (metricData) {
this.setData(metricData);
}
// Some other initializations related to book
};
Metric.prototype = {
setData: function(metricData) {
angular.extend(this, metricData);
},
delete: function() {
$http.delete('https://n4nite-api-n4nite.c9users.io/v1/imm/metrics/' + metricId);
},
update: function() {
$http.put('https://n4nite-api-n4nite.c9users.io/v1/imm/metrics/' + metricId, this);
},
hasMetadata: function() {
if (!this.metric.metadata || this.metric.metadata.length === 0) {
return false;
}
return this.metric.metadata.some(function(metadata) {
return true
});
}
};
return Metric;
}]);
})();
metricManager.js
(function () {
'use strict';
angular.module('app.metricManager', [])
.factory('metricManager', ['$http', '$q', 'Metric', function($http, $q, Metric) {
var metricManager = {
_pool: {},
_retrieveInstance: function(metricId, metricData) {
var instance = this._pool[metricId];
if (instance) {
instance.setData(metricData);
} else {
instance = new Metric(metricData);
this._pool[metricId] = instance;
}
return instance;
},
_search: function(metricId) {
return this._pool[metricId];
},
_load: function(metricId, deferred) {
var scope = this;
$http.get('https://n4nite-api-n4nite.c9users.io/v1/imm/metrics/' + metricId).then(successCallback, errorCallback)
function successCallback(metricData){
//success code
var metric = scope._retrieveInstance(metricData.id, metricData);
deferred.resolve(metric);
};
function errorCallback(error){
//error code
deferred.reject();
}
},
/* Public Methods */
/* Use this function in order to get a metric instance by it's id */
getMetric: function(metricId) {
var deferred = $q.defer();
var metric = this._search(metricId);
if (metric) {
deferred.resolve(metric);
} else {
this._load(metricId, deferred);
}
return deferred.promise;
},
/* Use this function in order to get instances of all the metrics */
loadAllMetrics: function() {
var deferred = $q.defer();
var scope = this;
$http.get('ourserver/books')
.success(function(metricsArray) {
var metrics = [];
metricsArray.forEach(function(metricData) {
var metric = scope._retrieveInstance(metricData.id, metricData);
metrics.push(metric);
});
deferred.resolve(metrics);
})
.error(function() {
deferred.reject();
});
return deferred.promise;
},
/* This function is useful when we got somehow the metric data and we wish to store it or update the pool and get a metric instance in return */
setMetric: function(metricData) {
var scope = this;
var metric = this._search(metricData.id);
if (metric) {
metric.setData(metricData);
} else {
metric = scope._retrieveInstance(metricData);
}
return metric;
},
};
return metricManager;
}]);
})();
Snippet from App.routes
.state('root.metric', {
url: 'metric',
data: {
title: 'Metric',
breadcrumb: 'Metric'
},
views: {
'content#': {
templateUrl: 'core/features/metric/metric.html',
controller: 'MetricController',
controllerAs: 'MEC'
}
}
})
Console
You are mixing two concepts controller alias and $scope, in your case you are creating controller alias as MEC using controllerAs. If you are using controller alias then this will work fine for you :
function MetricController($scope, metricManager, $log) {
var MEC = this;
metricManager.getMetric(0).then(function(metric) {
MEC.metric = metric
$log.info('$scope.metric printed to console below:');
$log.info($scope.metric);
})
}
If you don't want to use controller alias and share data between view and controller via $scope then in your view you should use something like this {{::metric.metadata.name}} and controller function should stay as it is.
PS: If you are using alias then MEC in var MEC = this can be MEC or abc or any name you like but convention is to use var vm = this and controllerAs: 'vm'. If you have controllerAs: 'xyz' then in your view xyz should be used to access model.
Problem with your view HTML, you need to use proper Angular expressions while binding. When you want use ::MEC alias name you need to mark your controller with as keyowrd, like ng-controller="xyz as MEC". And checkout working Plunker
<div class="panel panel-primary">
<div class="panel-body">
<!-- Try First Way to Print Results -->
Id: <span ng-bind="metric.id"></span>
<br> Name1:
<input type="text" ng-model="metric.metadata.name" />
<br><br><br><br>
<!-- Try Second Way to Print Results -->
<p data-ng-repeat="thing in [metric] track by $index">
{{$index + 1}}. <span>{{thing.metadata.name}}</span>
<span class="glyphicon glyphicon-info-sign"></span>
</p><br><br><br>
<!-- Try Third Way to Print Results -->
Id: <span ng-bind="metric.metricId"></span>
<br> Id: <span ng-bind="metric.id"></span>
<br><br><br>
<!-- Try Fourth Way to Print Results -->
Id: <strong>{{::metric.id}}</strong>
<br> Name: <strong>{{::metric.metadata.name}}</strong>
<br> Height: <strong>{{::metric.type}}</strong>
</div>
</div>

AngularJs is empty list

I make simple program with .net Core and AngularJs + webApi
My Api code as below
There is no Js error after running the problem is factory return nothing.
when I set break point on $location.qwets = index.query(); my "qwets" is empty the length of "qwets" is 0.
The get method is working each time page refresh but result is nothing.
I changed the code now I have results in 'qwets' but index is still empty
Thank you
// GET: api/values
[HttpGet]
public IEnumerable<ApplicationUser> Get()
{
return new List<ApplicationUser> {
new ApplicationUser {Id="test", Email="test1#test.com" },
new ApplicationUser {Id="tst2",Email="test2#test.com" }
};
}
app.js File is
(function () {
'use strict';
angular.module('saniehhaApp', [
// Angular modules
//'ngRoute'
// Custom modules
"indexService"
// 3rd Party Modules
]);
})();
(function () {
'use strict';
angular
.module('saniehhaApp')
.controller('indexController', indexController);
indexController.$inject = ['$location', 'index'];
function indexController($location, index) {
index.query()
.$promise.then(function (result) {
$scope.qwets = result;
}
})();
(function () {
'use strict';
var indexService = angular.module('indexService', ['ngResource']);
indexService.factory('index', ['$resource',
function ($resource) {
return $resource('/api/index/', {}, {
query:
{
method: 'GET',
params: {},
isArray: true
}
});
}]);
})();
and my index.html file
<!DOCTYPE html>
<html ng-app="saniehhaApp">
<head>
<meta charset="utf-8" />
<title>SampleTest</title>
<script src="vendor/angular.min.js"></script>
<script src="vendor/angular-resource.min.js"></script>
<script src="vendor/angular-route.min.js"></script>
<script src="scripts/app.js"></script>
</head>
<body ng-cloak>
<div ng-controller="indexController"></div>
<h2>list of users</h2>
<ul>
<li ng-repeat="qwet in qwets">
<p> "{{qwet.Id}}" - {{qwet.Email}}</p>
</li>
</ul>
</body>
</html>
You are using $location and not $scope in the controller to assign properties needed in the view. The view doesn't see things in $location
Change to
function indexController($scope, index) {
/* jshint validthis:true */
$scope.qwets = index.query();
}
As mentioned in comments above, $resource will initially return an empty array (or object) that will subsequently be populated when the actual request completes and internal watchers will then update view when it arrives
Also bad end "div" in HTML ng-repeat not in div controller

AngularJS ng-controller directive does not accept variable (scope function) from javascript, does not give any error either

I am relatively new to angularJS, I am trying to set up a page where inturn multiple pages are called depending upon the selection made previously.
All the pages have their own controller, so I am trying to set the controller and view src through the javascript and using them in HTML tags.
Following is what I am doing:
HTML page:
<div ng-if="sidebarName=='sidebar-device-wire'">
<div ng-controller="getSidebarCtlr">
<div ng-include src="sidebarSrc"></div>
</div>
</div>
javascript:
$scope.sidebarSrc="views/sidebars/sidebar-device.html";
$scope.sidebarCtlr="SidebarDeviceCtrl";
$scope.getSidebarCtlr = function(){return $scope.sidebarCtlr;}
For some reason though, this does not work. i can get the HTML page but the controller is not being called. Can anyone please tell me what I am doing wrong?
I would also recommend to use ngRoute or ui.router because there are many features that aren't easy to implement from scratch (like named views, nested views / nested states or resolves) and these modules are well tested.
Not sure why your controller isn't running but I guess that the expression of the controller is evaluated before your controller that is setting the name is running. So it will be always undefined at compile time.
But if you really like to implement a very basic router you could do it like in the following demo (or in this fiddle).
Update 21.12.2015
Here are some router examples that I wrote for other SO questions:
simple ui.router example - jsfiddle
more complex nested state example ui.router - jsfiddle
dynamic link list with ngRoute - jsfiddle
Please also have a look at ui.router github pages to learn more about it.
angular.module('simpleRouter', [])
.directive('simpleView', simpleViewDirective)
.provider('simpleRoutes', SimpleRoutesProvider)
.controller('MainController', MainController)
.controller('HomeController', HomeController)
.config(function(simpleRoutesProvider) {
simpleRoutesProvider.state([{
url: '/',
templateUrl: 'home.html',
controller: 'HomeController'
}, {
url: '/view1',
templateUrl: 'view1.html'
}, {
url: '/view2',
templateUrl: 'view2.html',
controller: function($scope) {
$scope.test = 'hello from controller'
}
}]);
simpleRoutesProvider.otherwise('/');
})
function HomeController($scope) {
$scope.hello = 'hello from home controller!!';
console.log('home controller started')
}
function MainController($scope) {
$scope.hello = 'Main controller test';
}
function simpleViewDirective() {
return {
restrict: 'EA',
scope: {},
template: '<div ng-include="templateUrl"></div>',
controller: function($scope, $location, $controller, simpleRoutes) {
var childControllerInst;
$scope.templateUrl = simpleRoutes.currentRoute.templateUrl || simpleRoutes.otherwise.templateUrl;
$scope.$watch(function() {
return $location.path();
}, function(newUrl) {
//console.log(newUrl)
$scope.templateUrl = simpleRoutes.changeRoute(newUrl);
childControllerInst = $controller(simpleRoutes.currentRoute.controller || function() {}, {$scope: $scope});
});
$scope.$on('$destroy', function() {
childControllerInst = undefined;
})
},
link: function(scope, element, attrs) {
}
}
}
function SimpleRoutesProvider() {
var router = {
currentRoute: {
templateUrl: ''
},
states: [],
otherwise: {},
changeRoute: function(url) {
var found = false;
angular.forEach(router.states, function(state) {
//console.log('state', state);
if (state.url == url) {
router.currentRoute = state;
found = true;
}
});
if (!found) router.currentRoute = router.otherwise;
//console.log(router.currentRoute);
return router.currentRoute.templateUrl;
}
};
this.state = function(stateObj) {
router.states = stateObj;
};
this.otherwise = function(route) {
angular.forEach(router.states, function(state) {
if (route === state.url ) {
router.otherwise = state;
}
});
//console.log(router.otherwise);
};
this.$get = function simpleRoutesFactory() {
return router;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="simpleRouter" ng-controller="MainController">
<script type="text/ng-template" id="home.html">home route {{hello}}</script>
<script type="text/ng-template" id="view1.html">view1</script>
<script type="text/ng-template" id="view2.html">view2 {{test}}</script>
<div simple-view="">
</div>
home
view1
view2
<br/>
{{hello}}
</div>
What's that code means? $scope.getSidebarCtlr = function(){return $scope.sidebarCtlr;}
the ng-directive requires a Controller name, its argument type is string and you cannot pass a simple function, you need to register a valid controller associating it to a module via the controller recipe.
https://docs.angularjs.org/guide/controller
angular.module('test', []).controller('TestCtrl', function($scope) {
$scope.greetings = "Hello World";
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<section ng-app="test">
<article ng-controller="TestCtrl">{{ greetings }}</article>
</section>

how to use services in angularjs to share data across multiple controllers?

I want to share data across multiple controllers in angularjs without using $rootScope. I am learning to use services for the same. What is wrong with the following code?
This is my controllers.js :
function Ctrl1(shareData) {
shareData.setValue("my_data");
}
function Ctrl2($scope, shareData) {
$scope.value = shareData.getvalue();
}
This is my services.js :
angular.module('connectionsServices').
factory('shareData', function() {
var shareVar = 'undefined';
return {
getValue: function() {
return shareVar;
},
setValue: function(value) {
shareVar = value;
}
}
});
But it is not working.
You can't bind service variable to controller variable, your code is changing shareVar but you are unable to see it, you can update the view like this:
HTML:
<div ng-app="testApp">
<div ng-controller="Ctrl2">{{ value }}
<br />
<div ng-controller="Ctrl1">
<button type="button" ng-click="change(); update();">Change me!</button>
</div>
</div>
</div>
JS:
angular.module('testApp', []).factory('shareData', function ($window) {
var shareVar = 'undefined';
return {
getValue: function () {
return shareVar;
},
setValue: function (value) {
shareVar = value;
}
};
});
function Ctrl1($scope, $window, shareData) {
$scope.change = function () {
shareData.setValue("my_data");
};
}
function Ctrl2($scope, shareData) {
$scope.value = shareData.getValue();
$scope.update = function () {
$scope.value = shareData.getValue();
};
}
Services provide an easy way for us to share data and functionality
throughout our app. The services we create are singletons that can be
injected into controllers and other services, making them the ideal
place for writing reusable code.
Follow its link https://thinkster.io/a-better-way-to-learn-angularjs/services

Categories

Resources