winjs angular typescript with splitView - angularjs

I'm trying to use winjs with angular and typescript.
The Angular-Winjs wrapper is working good as long I don't have to use some additional JavaScript for the Dom-Elements.
In my case I want to use the split-view item:
The menu gets displayed but the JavaScript-functionallity is not working.
this is my Code:
<win-split-view-pane-toggle split-view="splitViewElement"></win-split-view-pane-toggle>
<win-split-view id="splitView">
<win-split-view-pane>
SplitView Navigation Pane
<win-split-view-command label="'Home'" icon="'home'" on-invoked="goToHome()"></win-split-view-command>
<win-split-view-command label="'Settings'" icon="'settings'" on-invoked="goToSettings()"></win-split-view-command>
</win-split-view-pane>
<win-split-view-content>SplitView Content Area</win-split-view-content>
</win-split-view>
this is the example Code from the github-project-side.
their example also says that I have to add this to my Controller:
angular.module("yourAngularApp", ["winjs"]).controller("yourController", function ($scope) {
$scope.splitViewElement = document.getElementById("splitView");
});
now my problem is that I'm using typescript and create my Controller with the controllerAs-Syntax. When I add
$scope.splitViewElement = document.getElementById("splitView");
to my controller, the splitView-Element is NULL.
I also tried to use
angular.element("splitView").context
which has an element but it doesn't work, too.
this is my Controller.
constructor($scope, $state, $http, $q) {
super($state, $http, $q, $scope, true);
$scope.splitViewElement = document.getElementById("splitView"); //this is null
$scope.splitViewElement = angular.element("splitView").context; //this is not null
}

Might be late but here is how it works for me. In my controller I'm querying for the element with angular.element
vm.splitViewElement = angular.element("#splitView")[0];
If the element is available it should be the first in the array. Now simply bind the vm.splitViewElement to your view:
<win-split-view-pane-toggle class="win-splitviewpanetoggle" split-view="vm.splitViewElement">
</win-split-view-pane-toggle>

Related

AnchorScroll only works after second click

I believe I am experiencing the same issue mentioned here: $anchorScroll and $location only work after second try
I reviewed the plunker that works and I have routing in place, but it is still taking two clicks. I am using ng-route and not ui-router. How can I prevent it taking two clicks to get anchorScroll to work? As the first wants to cause a route to be established versus scrolling to the appropriate anchor.
Here is the click:
<a data-ng-click="gotoRequests()">Requests</a>
Here is the destination:
<div id="pendingrequests"></div>
Here is the function in my controller:
$scope.gotoRequests = function() {
// set the location.hash to the id of
// the element you wish to scroll to.
$location.hash('pendingrequests');
// call $anchorScroll()
$anchorScroll();
};
I was able to solve it using one of the answers here: How to handle anchor hash linking in AngularJS
by creating the following function:
$scope.scrollTo = function(id) {
var old = $location.hash();
$location.hash(id);
$anchorScroll();
//reset to old to keep any additional routing logic from kicking in
$location.hash(old);
};
I would call this as follows:
Yipee
<div id="pendingrequests"></div>
Latest Update
From AngularJS 1.4.0 $anchorScroll allows you to directly pass the id as a parameter without the need to update the URL with the hash.
During click
<div data-ng-click="gotoRequests(pendingrequests)"> </div>
In Controller
$scope.gotoRequests = function(divId) { $anchorScroll(divId); }
I also had the same issue with angular 1 and I solved it using $timeout. Here is an example of how I did it
angular.module('app').controller('MyTestController', ['$scope', '$location', '$anchorScroll', '$timeout', function($scope, $location, $anchorScroll, $timeout) {
function scrollToElement (element, offset){
$timeout(function() {
$anchorScroll.yOffset = offset; // add extra pixels to scroll initially
var old = $location.hash();
$location.hash(element);
$anchorScroll();
$location.hash(old);
});
}
scrollToElement('element ID', 100);
}]);
You need to add $timer for 300 like:
this.gotoBottom = function(scrollId) {
$timeout(function() {
$location.hash(scrollId); $anchorScroll(scrollId);
}, 300);
}

Angular Dependencies Between Modules

I'm facing a problem using Dependency Injection between modules.
I have a module that implements a directive I need to use in other applications.
I added the dependency from this module in another app declaration like this:
angular.module('mainApp', ['ngRoute', 'directiveApp']);
However, the methods implemented into directiveApp.controller, doesn't seem to be visible from a page of MainApp, since the directive can't run a method it needs from their controller.
I know it's a little confusing, so I put an example in this plunker, that shows the problem I'm facing.
When you inject another module into your own, the controllers and directives it implements become available, but you need to use them properly.
The way you are trying to do is not possible, you can do something like this:
http://plnkr.co/edit/peHH226vxtkI48RFZ3Eq?p=preview
<body ng-controller="MainCtrl">
<h1>Value: {{name}}!</h1>
<button ng-click="mainModule()">Call a function in the main module!</button>
<div ng-controller="SubCtrl">
{{name}}
<button ng-click="dependentModule()">Call a function in the dependent module!</button>
</div>
</body>
But notice that you have two different $scopes and consequently two different name variables.
That means your dependentModule() function belongs to your SubCtrl and you can only use it inside its own $scope
That's not recommended, but if you really need to, you can use the other controllers on your own methods and then copy the results:
http://plnkr.co/edit/ranK9n08NNVuSKIGX15G?p=preview
main.controller("MainCtrl", function($scope, $controller) {
$scope.name = "Initial value";
$scope.mainModule = function() {
$scope.name = "a function in the same module";
};
$scope.bridgeFunction = function(){
// Create a new scope
var injectedScope = $scope.$new();
// Use it on the other controller
$controller('SubCtrl',{$scope : injectedScope });
// Call the methdo on the controller
testCtrl1ViewModel.dependentModule(); //And call the method on the newScope.
// Copy the result from that scope into your own
$scope.name = testCtrl1ViewModel.name;
}
});
A third option is to merge the two scopes, although this can get very messy, it is possible:
http://plnkr.co/edit/1NKStMuYy0e00dhuWKUD?p=preview
main.controller("MainCtrl", function($scope, $controller) {
$scope.name = "Initial value";
//This can get very messy, but it is possible to merge the two scopes:
$controller('SubCtrl',{$scope : $scope });
$scope.mainModule = function() {
$scope.name = "a function in the same module";
};
});
Hope that helps

How do I inject a controller into another controller in AngularJS

I'm new to Angular and trying to figure out how to do things...
Using AngularJS, how can I inject a controller to be used within another controller?
I have the following snippet:
var app = angular.module("testApp", ['']);
app.controller('TestCtrl1', ['$scope', function ($scope) {
$scope.myMethod = function () {
console.log("TestCtrl1 - myMethod");
}
}]);
app.controller('TestCtrl2', ['$scope', 'TestCtrl1', function ($scope, TestCtrl1) {
TestCtrl1.myMethod();
}]);
When I execute this, I get the error:
Error: [$injector:unpr] Unknown provider: TestCtrl1Provider <- TestCtrl1
http://errors.angularjs.org/1.2.21/$injector/unpr?p0=TestCtrl1Provider%20%3C-%20TestCtrl1
Should I even be trying to use a controller inside of another controller, or should I make this a service?
If your intention is to get hold of already instantiated controller of another component and that if you are following component/directive based approach you can always require a controller (instance of a component) from a another component that follows a certain hierarchy.
For example:
//some container component that provides a wizard and transcludes the page components displayed in a wizard
myModule.component('wizardContainer', {
...,
controller : function WizardController() {
this.disableNext = function() {
//disable next step... some implementation to disable the next button hosted by the wizard
}
},
...
});
//some child component
myModule.component('onboardingStep', {
...,
controller : function OnboadingStepController(){
this.$onInit = function() {
//.... you can access this.container.disableNext() function
}
this.onChange = function(val) {
//..say some value has been changed and it is not valid i do not want wizard to enable next button so i call container's disable method i.e
if(notIsValid(val)){
this.container.disableNext();
}
}
},
...,
require : {
container: '^^wizardContainer' //Require a wizard component's controller which exist in its parent hierarchy.
},
...
});
Now the usage of these above components might be something like this:
<wizard-container ....>
<!--some stuff-->
...
<!-- some where there is this page that displays initial step via child component -->
<on-boarding-step ...>
<!--- some stuff-->
</on-boarding-step>
...
<!--some stuff-->
</wizard-container>
There are many ways you can set up require.
(no prefix) - Locate the required controller on the current element. Throw an error if not found.
? - Attempt to locate the required controller or pass null to the link fn if not found.
^ - Locate the required controller by searching the element and its parents. Throw an error if not found.
^^ - Locate the required controller by searching the element's parents. Throw an error if not found.
?^ - Attempt to locate the required controller by searching the element and its parents or pass null to the link fn if not found.
?^^ - Attempt to locate the required controller by searching the element's parents, or pass null to the link fn if not found.
Old Answer:
You need to inject $controller service to instantiate a controller inside another controller. But be aware that this might lead to some design issues. You could always create reusable services that follows Single Responsibility and inject them in the controllers as you need.
Example:
app.controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) {
var testCtrl1ViewModel = $scope.$new(); //You need to supply a scope while instantiating.
//Provide the scope, you can also do $scope.$new(true) in order to create an isolated scope.
//In this case it is the child scope of this scope.
$controller('TestCtrl1',{$scope : testCtrl1ViewModel });
testCtrl1ViewModel.myMethod(); //And call the method on the newScope.
}]);
In any case you cannot call TestCtrl1.myMethod() because you have attached the method on the $scope and not on the controller instance.
If you are sharing the controller, then it would always be better to do:-
.controller('TestCtrl1', ['$log', function ($log) {
this.myMethod = function () {
$log.debug("TestCtrl1 - myMethod");
}
}]);
and while consuming do:
.controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) {
var testCtrl1ViewModel = $controller('TestCtrl1');
testCtrl1ViewModel.myMethod();
}]);
In the first case really the $scope is your view model, and in the second case it the controller instance itself.
I'd suggest the question you should be asking is how to inject services into controllers. Fat services with skinny controllers is a good rule of thumb, aka just use controllers to glue your service/factory (with the business logic) into your views.
Controllers get garbage collected on route changes, so for example, if you use controllers to hold business logic that renders a value, your going to lose state on two pages if the app user clicks the browser back button.
var app = angular.module("testApp", ['']);
app.factory('methodFactory', function () {
return { myMethod: function () {
console.log("methodFactory - myMethod");
};
};
app.controller('TestCtrl1', ['$scope', 'methodFactory', function ($scope,methodFactory) { //Comma was missing here.Now it is corrected.
$scope.mymethod1 = methodFactory.myMethod();
}]);
app.controller('TestCtrl2', ['$scope', 'methodFactory', function ($scope, methodFactory) {
$scope.mymethod2 = methodFactory.myMethod();
}]);
Here is a working demo of factory injected into two controllers
Also, I'd suggest having a read of this tutorial on services/factories.
There is no need to import/Inject your controller in JS. You can just inject your controller/nested controller through your HTML.It's worked for me.
Like :
<div ng-controller="TestCtrl1">
<div ng-controller="TestCtrl2">
<!-- your code-->
</div>
</div>
you can also use $rootScope to call a function/method of 1st controller from second controller like this,
.controller('ctrl1', function($rootScope, $scope) {
$rootScope.methodOf2ndCtrl();
//Your code here.
})
.controller('ctrl2', function($rootScope, $scope) {
$rootScope.methodOf2ndCtrl = function() {
//Your code here.
}
})
<div ng-controller="TestCtrl1">
<div ng-controller="TestCtrl2">
<!-- your code-->
</div>
</div>
This works best in my case, where TestCtrl2 has it's own directives.
var testCtrl2 = $controller('TestCtrl2')
This gives me an error saying scopeProvider injection error.
var testCtrl1ViewModel = $scope.$new();
$controller('TestCtrl1',{$scope : testCtrl1ViewModel });
testCtrl1ViewModel.myMethod();
This doesn't really work if you have directives in 'TestCtrl1', that directive actually have a different scope from this one created here.
You end up with two instances of 'TestCtrl1'.
The best solution:-
angular.module("myapp").controller("frstCtrl",function($scope){
$scope.name="Atul Singh";
})
.controller("secondCtrl",function($scope){
angular.extend(this, $controller('frstCtrl', {$scope:$scope}));
console.log($scope);
})
// Here you got the first controller call without executing it
use typescript for your coding, because it's object oriented, strictly typed and easy to maintain the code ...
for more info about typescipt click here
Here one simple example I have created to share data between two controller using Typescript...
module Demo {
//create only one module for single Applicaiton
angular.module('app', []);
//Create a searvie to share the data
export class CommonService {
sharedData: any;
constructor() {
this.sharedData = "send this data to Controller";
}
}
//add Service to module app
angular.module('app').service('CommonService', CommonService);
//Create One controller for one purpose
export class FirstController {
dataInCtrl1: any;
//Don't forget to inject service to access data from service
static $inject = ['CommonService']
constructor(private commonService: CommonService) { }
public getDataFromService() {
this.dataInCtrl1 = this.commonService.sharedData;
}
}
//add controller to module app
angular.module('app').controller('FirstController', FirstController);
export class SecondController {
dataInCtrl2: any;
static $inject = ['CommonService']
constructor(private commonService: CommonService) { }
public getDataFromService() {
this.dataInCtrl2 = this.commonService.sharedData;
}
}
angular.module('app').controller('SecondController', SecondController);
}

AngularJS: global access to function defined in a controller

I have an angularjs app with some controllers.
At some point, I need to access a function defined inside a controller, but the place where the function is gonna be called is not inside the angularjs APP.
I'll try to build a simple scenario:
app.controller('TaskController', function ($scope, $routeParams, $window, TaskEngine, PortalUtil) {
$scope.closeTask = function() {
$scope.openTask = false;
$scope.openedTaskUrl = undefined;
}
});
-- Some other place in my web app, outside of the angular APP.
<button onclick="closeTask();">
The "closeTask()" function is never accessible, because its out of scope.
I tried to define it in the window object
$window.closeTask = function() {
$scope.openTask = false;
$scope.openedTaskUrl = undefined;
}
});
Now, my function is visible, but the variables "openTask" and "openedTaskUrl" are not.
Is it possible to do what I want?
Basically, I have a controller, and I need to access one function anywhere, to control the behaviour of a menu.
Thanks!
I would not use $window for this. Instead, Angular has a nice feature which lets not Angular code to interact with it. Using Angular.element you can access data or functions defined in Angulars Scope.
var $scope = angular.element(document.querySelector('[ng-app=app]')).scope();
$scope.$apply(function() {
$scope.print("Hello world");
});

Trying to get a string from Angular UI Modal via resolve object

I'm using the Angular UI modal directive: http://angular-ui.github.io/bootstrap/
I'm trying to pass a string from my modal open() function to my modal controller via the resolve object. I feel like I'm doing the right thing, but somehow it isn't working.
Modal open() function:
$scope.showCommentModal = function () {
var modalInstance = $modal.open({
templateUrl: "templates/text-entry-modal.html",
controller: "TextEntryModalCtrl",
resolve: {
value: function () {
alert("VALUE");
return "Hello"
}
}
});
};
Modal controller:
.controller("TextEntryModalCtrl", ["$scope", "$modalInstance", function ($scope, $modalInstance, value) {
alert(value);
$scope.value = value;
$scope.cancel = function () {
$modalInstance.dismiss("cancel");
};
}]);
The alert in the open function shows every time, right before the alert from the controller, so it's doing something, but when it gets to the controller, value is undefined.
One thing to note is that these controllers are not global variables. The example in the link above is using those, but that's not best practice for us.
Also, I have read this post: Angular-ui modal, sending data into modal controller from $http
I feel like this is very close to the answer I'm looking for, but I don't think I'm waiting on a promise to resolve in this case, am I? As far as I can tell, our implementations are very similar, but again I'm not using global variables but they are. Or maybe I just don't understand what's actually going on here. Of course, I don't have enough points to just ask that, so here I am...
Looking at the first line of the modal controller, it appears the array that is the second parameter is missing "value", as the third item in the array (just before the final function in the array). It should be:
.controller("TextEntryModalCtrl", ["$scope", "$modalInstance", "value", function ($scope, $modalInstance, value) {
This particular bit of syntax is using the controller() method to add a constructor function to the TextEntryModalCtrl controller using Angular's inline injection annotation to explicitly specify both the dependencies of your controller along with the constructor function that will ultimately consume those (injected) dependencies.
Though your constructor function was written to consume 3 dependencies, you had only explicitly listed the first 2 dependencies so the value dependency was lost.
https://docs.angularjs.org/guide/controller#setting-up-the-initial-state-of-a-scope-object
https://docs.angularjs.org/guide/di#inline-array-annotation

Resources