How to make scope functions available to compiled template in angular - angularjs

I am trying to write a service, which will compile HTML for a directive and append it to the body element. While the text is being processed by the directive the functions are not.
Here's a simpler version which I am not able to do the same with ng-click directive and compiling it from the controller. Can anyone please tell me how I can achieve this. My goal is to create a very basic directive similar in functionality to that of modals from angular ui-bootstrap or dialog service from Angular material.
angular
.module('app', [])
.controller('ctrl', ctrl);
function ctrl($scope, $compile) {
var html = '',
newScope = $scope.$new(true),
newScope1 = $scope.$new(true);
$scope.text = 'from controller';
$scope.fun = function() {
alert('from controller');
};
newScope.text = 'from controller with new scope';
newScope.fun = function() {
alert('from controller with new scope');
};
newScope1.text = 'from controller with new scope1';
newScope1.fun = function() {
alert('from controller with new scope1');
};
html = $compile('<button ng-click="fun">{{text}}</button>')($scope);
angular.element('body').append(html);
html = $compile('<button ng-click="fun">{{text}}</button>')(newScope);
angular.element('body').append(html);
$compile('<button ng-click="fun">{{text}}</button>')(newScope1, function(clonedElement, scope) {
console.log(clonedElement, scope);
angular.element('body').append(clonedElement);
});
}
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="ctrl">
<h1>Hello Plunker!</h1>
</body>
</html>
plunkr

you're doing it right just call the method use ng-click="fun()" instead of ng-click="fun"(the only thing missing)
html = $compile('<button ng-click="fun()">{{text}}</button>')(newScope);

Related

Why does my Javascript File not load into html after I use $sce.trustAsHtml("<div id='boo'></div>");

I am trying to load Vexflow sheetmusic into Div Dynamically through angularja ng-bind-html with $sce.trustAsHtml("<div id='boo'></div>"). This Works With $sce.trustAsHtml("<p>Hello World</p>"). Putting <div id='boo'></div> in body of page works also. It will not load sheet music into div with ng-bind-html with $sce.trustAsHtml("<div id='boo'></div>").
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9 /angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-sanitize.js"></script>
<script src="https://unpkg.com/vexflow/releases/vexflow-debug.js"> </script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-bind-html="html"></div>
</div>
<script>
var app = angular.module("myApp", ['ngSanitize']);
app.controller("myCtrl", function($scope, $sce) {
$scope.html = $sce.trustAsHtml("<div id='boo'></div>");
});
id = "boo";
len =window.innerWidth/2;
VF = Vex.Flow;
// Create an SVG renderer and attach it to the DIV element named "boo".
var div = document.getElementById(id);
var renderer = new VF.Renderer(div, VF.Renderer.Backends.SVG);
// Size our svg:
renderer.resize(window.innerWidth/2 , 200);
// And get a drawing context:
var context = renderer.getContext();
// Create a stave at position 0, 40 of width of 'len' on the canvas.
var stave = new VF.Stave(0, 40, len);
// Add a clef and time signature.
stave.addClef("treble").addTimeSignature("4/4");
// Connect it to the rendering context and draw!
stave.setContext(context).draw();
</script>
</body>
</html>
I would like the JS file to load after angular.
For code attached to an element, use a custom directive:
app.directive("booDirective", function() {
return {
link: postLink
};
function postLink(scope,elem,attrs) {
var div = elem[0];
var renderer = new VF.Renderer(div, VF.Renderer.Backends.SVG);
//...
}
});
Usage
<div boo-directive></div>
When the AngularJS framework compiles DOM, it invokes the link function of any attached directives.
Note: The ng-bind-html does not compile added DOM. However core directives such as ng-include, ng-view, ng-repeat, ng-if, etc. compile templates before adding them to the DOM.
For more information, see
AngularJS Developer Guide - Creating Custom Directives
This works now. I had my own errors. Thanks for help
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-sanitize.js"></script>
<script src="https://unpkg.com/vexflow/releases/vexflow-debug.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<div boo-directive></div>
</div>
<script>
var app = angular.module("myApp", []);
app.controller('myCtrl', function($scope) {
});
app.directive("booDirective", function() {
return {
link: postLink
};
function postLink(scope,elem,attrs) {
var len =window.innerWidth/2;
var VF = Vex.Flow;
var div = elem[0];
var renderer = new VF.Renderer(div, VF.Renderer.Backends.SVG);
// Size our svg:
renderer.resize(window.innerWidth/2 , 200);
// And get a drawing context:
var context = renderer.getContext();
// Create a stave at position 0, 40 of width of 'len' on the canvas.
var stave = new VF.Stave(0, 40, len);
// Add a clef and time signature.
stave.addClef("treble").addTimeSignature("4/4");
// Connect it to the rendering context and draw!
stave.setContext(context).draw();
}
});
</script>
</body>
</html>

AngularJS Directive Template is not display

I start learning AngularJS today with directive ... I can't get directive work. Please help
<html ng-app="ngBasic">
<head>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
var app = angular.module('ngBasic', []);
app.controller('ngBasicCtrl', function($scope) {
$scope.age = 20;
});
app.directive('myDirective', function($scope) {
return {
template: '<h1>{{age}}</h1>'
}
});
</script>
</head>
<body ng-controller="ngBasicCtrl">
<h1>{{age}}</h1>
<my-directive></my-directive>
<div my-directive></div>
<div class='my-directive'></div>
</body>
</html>
https://jsfiddle.net/bigzidane/t8Lv3mpg/2/
Currently, the page onlys show 20. Expecting tag but not displaying yet.
Use the scope option to create an isolated scope the template can refer to :
app.directive('myDirective', function() {
return {
scope: {
age: '='
},
template: '<h1>{{age}}</h1>'
}
});
Now you can pass the controller $scope's age to the directive scope, for example this way :
<my-directive age="age+1"></my-directive>
Will render out 21. Updated fiddle -> https://jsfiddle.net/t8Lv3mpg/3/
You have to remove the $scope from the function returning your directive as it does not take a $scope parameter.
app.directive('myDirective', function() {
return {
template: '<h1>{{age}}</h1>'
}
});

How to use window.onload in angular js controller?

How to use window.onload function inside a controller.
window.onload= function() {
console.log("Hi Page loaded")
};
The controller is not applicable for the full page.
I want to execute a function after my controller loads at-least.
You can use ng-init and invoke your necessary function using the same directive
var app = angular.module('DemoApp', [])
app.controller('akuaController', function($scope) {
$scope.load = function() {
alert("Window is loaded");
}
});
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.4.7" data-semver="1.4.7" src="https://code.angularjs.org/1.4.7/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-filter/0.4.7/angular-filter.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="DemoApp" ng-controller="akuaController">
<div ng-init="load()">
</div>
</body>
</html>
Changing the example from Angular $window
Your Controller
angular.module('windowExample', [])
.controller('ExampleController', ['$scope', '$window', function($scope, $window) {
$scope.greeting = 'Hello, World!';
$scope.doGreeting = function(greeting) {
// This would be a starting point
$window.onload(greeting);
};
}]);
Your markup
<div ng-controller="ExampleController" ng-init="ExampleController.doGreeting()">
</div>
//inside your controller
$scope.$on('$viewContentLoaded', function() {
// write here
// either methods or variables
});

pass data to angular controller from a global function

See example below and the TODO in the send function : How can I assign the label value in the global send function to dropboxController dropbox.label
<!DOCTYPE html>
<html>
<head>
<script src="http://apps.bdimg.com/libs/angular.js/1.4.0-beta.4/angular.min.js"></script>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="script.js"></script>
<link rel="stylesheet" href="style.css" />
<script type="text/javascript">
window.onload=function() {
$('#AddIn').append("<div ng-app='dropboxApp' ng-controller='dropboxController as dropbox'>{{dropbox.label}}</div>");
angular.module('dropboxApp', [])
.controller('dropboxController', function () {
var dropbox = this;
dropbox.label = "hello angular";
});
angular.bootstrap($('#AddIn'), ['dropboxApp']);
}
function send(label)
{
//TODO assign label value to dropboxController dropbox.label
}
</script>
</head>
<body>
<div id="AddIn"></div>
<button onclick="send('new label');">Send</button>
</body>
</html>
Use angular.element and get scope of specific dom element and apply label to it.
Change dropbox.label to $scope.label and inject $scope in controller because this and $scope are different. Check 'this' vs $scope in AngularJS controllers
Keep in Mind: Here I have used myDiv which has scope for angular and added id in append div line.
It's better to use ng-click instead of onclick if possible.
window.onload = function() {
$('#AddIn').append("<div id='myDiv' ng-app='dropboxApp' ng-controller='dropboxController as dropbox'>{{label}}</div>");
angular.module('dropboxApp', [])
.controller('dropboxController', function($scope) {
var dropbox = this;
$scope.label = "hello angular";
});
angular.bootstrap($('#AddIn'), ['dropboxApp']);
}
function send(label) {
var scope = angular.element($("#myDiv")).scope();
scope.$apply(function() {
scope.label = label;
})
console.log(scope.label);
}
<!DOCTYPE html>
<html>
<head>
<script src="http://apps.bdimg.com/libs/angular.js/1.4.0-beta.4/angular.min.js"></script>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
</head>
<body>
<div id="AddIn"></div>
<button id="myButton" onclick="send('new label');">Send</button>
</body>
</html>

Bind data to controller after bootstrapping an AngularJS application

Is there any way to bind anything you could have written on a form before bootstrapping an AngularJS application?
For example, in this form (also executable in https://jsbin.com/womuyi). How could bind to the controller the data I've written on the input before clicking the bootstrap button?
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Angular Bootstrap Call Example">
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-controller="MainCtrl as vm">
Please type something before bootstrapping AngularJS
<form>
<input type="text" ng-model="vm.sth"><br/>
You wrote {{ vm.sth }}
</form>
<button onclick="doBootstrap()">Bootsrap AngularJS</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.min.js"></script>
<script>
angular
.module('main', [])
.controller('MainCtrl', function(){
var vm = this;
// How to bind what I wrote on the input after bootstrap??
});
function doBootstrap() {
angular.bootstrap(document, ['main']);
document.querySelector('button').disabled = 'disabled'
}
</script>
</body>
</html>
Quite ugly, but you can use document to store the values (or any other object that you want) to wait until your app is bootstrapped.
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Angular Bootstrap Call Example">
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-controller="MainCtrl as vm">
Please type something before bootstrapping AngularJS
<form>
<input id="sthInput" type="text" ng-model="vm.sth"><br/>
You wrote {{ vm.sth }}
</form>
<button onclick="doBootstrap()">Bootsrap AngularJS</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.min.js"></script>
<script>
angular
.module('main', [])
.controller('MainCtrl', function(){
var vm = this;
vm.sth = document.myBootstrap.sth;
});
function doBootstrap() {
var sthValue = document.querySelector("#sthInput");
document.myBootstrap = {
sth: sthValue.value
};
angular.bootstrap(document, ['main']);
}
</script>
</body>
</html>
Use ng-app directive before controller as below:
<body ng-app="main" ng-controller="MainCtrl as vm">
This will automatically do the bootstrapping for you.
The official documentation for the same can be found at https://docs.angularjs.org/api/ng/directive/ngApp.
you just save value of text box before bootstrap Angular App:-
`beforeData = (document.querySelectorAll(".beforeBootstrap")[0]).value;
angular.bootstrap(document, ['myApp']);
$event.target.disabled = 'disabled';`
see this plunker
I would approach this by doing something along the lines of processing input data before Bootstrap like #elecash suggested, but I would add it to a constant.
(function() {
'use strict';
window.doBootstrap = function() {
window.values = {};
var inputs = document.querySelectorAll('input'),
input;
for (var i = 0; i < inputs.length; i += 1) {
input = inputs[i];
window.values[input.getAttribute('ng-model')] = input.value;
}
angular.bootstrap(document, ['main']);
}
}());
Then in your Angular code:
angular
.module('main', [])
.controller('MainCtrl', ['preBootstrap', function(preBootstrap){
var vm = this;
angular.forEach(preBootstrap, function(value, key) {
var modifiedKey = key.replace('vm.', '');
this[modifiedKey] = value;
}, vm);
}])
.constant('preBootstrap', window.values);

Resources