Using web-browser control with angularjs - javascript

Trying to do below:
(a) Embedded a web browser control inside a winform.
(b) Pass a string data from winform control to webbrowser via Invoking a method in JS.
This JS method further calls the angularJS controller. Call is successful. However, the controller which is used in view does not gets updated.
Snippet below:
Invoking side C# winform snippet:
string testString = "testing";
webBrowser2.Document.InvokeScript("InvokeJSPassingTestString", new object[] { testString });
HTML Side.
<html ng-app="ManagerApp">
<head>
<meta charset="utf-8" />
<title></title>
<script src="Scripts/angular.js"></script>
<script type="text/javascript">
var angularApp = angular.module('ManagerApp', []);
angularApp.controller('ManagerCtrl', ['$scope', function ($scope) {
$scope.customParams = {};
$scope.updateCustomRequest = function (data) {
$scope.customParams.value = data;
alert("$scope.customParams.value :" + $scope.customParams.value);
};
}]);
function InvokeJSPassingTestString(data) {
var dom_el = document.querySelector('[ng-controller="ManagerCtrl"]')
var ng_el = angular.element(dom_el);
var ng_el_scope = ng_el.scope();
var test = ng_el_scope.updateCustomRequest(data);
}
</script>
</head>
<body ng-controller="ManagerCtrl">
Passed parameter from winform to JS to angularJs is as below:
{{ customParams.value }}
</body>
</>
In above snippet - I get the alert but the view {{ customParams.value }} does not gets updated.
Any inputs appreciated.

You code is running outside the angularjs digest cycle, so you need to start a new digest cycle after changing data
$scope.updateCustomRequest = function (data) {
$scope.$apply(function () {
$scope.customParams.value = data;
alert("$scope.customParams.value :" + $scope.customParams.value);
});
};
How to update bindings

Related

I am having trouble using bind to change the this statement to point to my controller Javascript MVC

I am trying to implement model view controller pattern in a simple print hello world program. I can get everything to work properly except at the end after I click the button in my program. I am trying to bind my function to the controller so that way the function uses the this statements in the controller to access my model and view instances in the controller. When I click the button the this statements in my function are referencing my button object instead of the controller. I am having trouble using bind to change what the this statements point to. Please, any assistance would be greatly appreciated. thank you.
<!DOCTYPE html>
<html lang="en">
<head>
<title> Hello World MVC </title>
<link rel="stylesheet" href="css file name">
</head>
<body>
<div id="container">
<input type=text id="textBox">
<button id="displayButton">Display</button>
</div>
<script src="mainbind.js"></script>
</body>
</html>
function Model(text) {
this.data = text;
};
function View() {
this.displayButton = document.getElementById('displayButton');
this.textBox = document.getElementById('textBox');
this.initialize = function(displayButtonProcess) {
this.displayButton.addEventListener('click', displayButtonProcess);
}
};
function Controller(text) {
this.model = new Model(text);
this.view = new View;
this.buttonClick = function(event) {
// process the button click event
this.view.textBox.value = this.model.data;
};
this.view.initialize(this.buttonClick);
};
let x = new Controller("Hello World");
x.buttonClick = x.buttonClick.bind(x);
The problem is that you are changing controller instance property after you have already used unbinded version as a callback.
You can fix it by binding directly when creating a controller. Or you should better use arrow functions instead.
this.buttonClick = () => this.view.textBox.value = this.model.value
function Model(text) {
this.data = text;
};
function View() {
this.displayButton = document.getElementById('displayButton');
this.textBox = document.getElementById('textBox');
this.initialize = function(displayButtonProcess) {
this.displayButton.addEventListener('click', displayButtonProcess);
}
};
function Controller(text) {
this.model = new Model(text);
this.view = new View;
this.buttonClick = function(event) {
// process the button click event
this.view.textBox.value = this.model.data;
};
this.view.initialize(this.buttonClick.bind(this));
};
let x = new Controller("Hello World");
// x.buttonClick = x.buttonClick.bind(x);
<div id="container">
<input type=text id="textBox">
<button id="displayButton">Display</button>
</div>

Angular.JS binding isn't working

I have an extremely simple setup here
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body ng-app="locationApp" ng-controller="locationController">
<button ng-click="getLocation()">Get Location</button>
<br />
Latitude: {{city.Latitude}} <br />
Longitude {{city.Longitude}} <br />
<script src="Scripts/lib/angular.min.js"></script>
<script src="Scripts/app.js"></script>
</body>
</html>
app.js:
var locationApp = angular.module('locationApp', []);
var locationController = locationApp.controller("locationController", function ($scope, $http) {
$scope.getLocation = function () {
$http.get("https://localhost:44320/api/location?cityName=sg").then(function (location) {
$scope.city = location;
});
}
});
When I click on the Get Location button, my bindings {{city.Latitude}} and {{city.Longitude}} remains blank.
I tried debugging by setting a break point in Chrome, and my values do show up. So I'm not sure what I'm missing. Any help?
I'm using AngularJS 1.6
The parameter passed to the then function is the response object. The response object contains the data:
$http.get("https://localhost:44320/api/location?cityName=sg").then(function (response) {
$scope.city = response.data;
});
Is the location returned the response from the web service?
Did you actually want to do:
$scope.city = location.data;
You want the data object returned in the get function.
Try $scope.city = location.data
Use $scope.apply() after getting the response to start the new digest.

AngularJS controller cannot store Youtube API response results to a variable

I'm trying to make a search request using youtube's API and store the result to a variable inside an AngularJS' controller.
This is my app.js file.
var app = angular.module('myApp', []);
app.controller('myController', ['$scope', function($scope){
this.data = '###';
this.search = function(){
var request = gapi.client.youtube.search.list({
part: 'snippet',
q: 'beatles'
});
request.execute(function(response){
var responseString = JSON.stringify(response, '', 2);
this.data = responseString;
// document.getElementById('response').innerHTML += this.data;
});
}
}]);
function onClientLoad() {
gapi.client.load('youtube', 'v3', onYouTubeApiLoad);
}
function onYouTubeApiLoad() {
gapi.client.setApiKey('blahblahblahblahblahblah');
}
and this is the index.html.
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
</head>
<body ng-controller="myController as c">
<div ng-click="c.search()" class="btn btn-success">
Press me!
</div>
<h2>Result</h2>
<pre id="response"> {{c.data}} </pre>
</body>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
<script src="https://apis.google.com/js/client.js?onload=onClientLoad" type="text/javascript"></script>
</html>
In the html code, there is a press me button which invokes the search() function which makes the request. The javascript console shows that the request was executed successfully.
I store the response result to a variable called data. The problem is that the content of the variable does not change. However, if I store this value inside the .innerHTML of a document element (the classic Javascript way), this works, and the results are shown successfully (this line is currently commented out).
Why response result cannot be stored in a variable that lives outside this function?
Please try like this.
app.controller('myController', ['$scope', function($scope){
var c = this;
c.search = function(){
var request = gapi.client.youtube.search.list({
part: 'snippet',
q: 'beatles'
});
request.execute(function(response){
var responseString = JSON.stringify(response, '', 2);
c.data = responseString;
});
}
console.log(c.data);
}]);
I am assuming gapi.client is not an angular library. The request for search is concluded outside angularjs and hence angular doesn't update scope with new response. You will have to call the digest cycle in callback of request.execute. Something like the following should work:
request.execute(function(response){
var responseString = JSON.stringify(response, '', 2);
this.data = responseString;
$scope.$digest();
});
I hope this helps.
Finally, the solution to the problem was a combination of the two answers above:
var app = angular.module('myApp', []);
app.controller('myController', ['$scope', '$q', function($scope, $q){
var c = this;
c.search = function(){
var request = gapi.client.youtube.search.list({
part: 'snippet',
q: 'beatles'
});
request.execute(function(response){
var responseString = JSON.stringify(response, '', 2);
c.data = responseString;
$scope.$digest();
});
};
}]);
we first need to set the controller itself to a variable with
var c = this;
and then we need to call $scope.$digest() as well to update the c.data value. Now right at the time the button is pressed, the result is shown in the page.

How to compile dynamic template from outside of angular?

I want to load dynamic HTML content via AJAX, then compile it, because it contains angular directives.
I have this class that uses methods that help using angular without being in the scope of an angular controller or directive:
var AngularHelper = (function () {
var AngularHelper = function () { };
/**
* ApplicationName : Default application name for the helper
*/
var defaultApplicationName = "MyApp";
/**
* Compile : Compile html with the rootScope of an application
* and replace the content of a target element with the compiled html
* #$targetDom : The dom in which the compiled html should be placed
* #htmlToCompile : The html to compile using angular
* #applicationName : (Optionnal) The name of the application (use the default one if empty)
*/
AngularHelper.Compile = function ($targetDom, htmlToCompile, applicationName) {
var $injector = angular.injector(["ng", applicationName || defaultApplicationName]);
$injector.invoke(["$compile", "$rootScope", function ($compile, $rootScope) {
//Get the scope of the target, use the rootScope if it does not exists
var $scope = $targetDom.html(htmlToCompile).scope();
$compile($targetDom)($scope || $rootScope);
$rootScope.$digest();
}]);
}
return AngularHelper;
})();
Then I use it after my jQuery successful ajax request:
<!DOCTYPE html>
<html>
<head>
<title>AngularJS Test</title>
</head>
<body>
<div id="contents"><!-- content --></div>
<script src="js/angular.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$.get( "http://fuiba.com/test/index.html", function( data ) {
$("#result").html(data);
AngularHelper.Compile('$("#result")', data);
});
});
</script>
</body>
</html>
But I get this error (see this codepen):
$targetDom.html is not a function
You need to pass a DOM element not a string as a first parameter in AngularHelper.Compile function,
so
AngularHelper.Compile($("#result"), data);
not
AngularHelper.Compile('$("#result")', data);

AngularJS insert alert box

I am completely new to AngularJS and have been stuck with this. I want to be able to conditionally display a Javascript alertbox on the page.
Suppose I want to do something like this:
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="personCtrl">
<script>{{warning}}</script>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('personCtrl', function($scope) {
$scope.warning = "alert('This is a warning');";
});
</script>
</body>
</html>
So I assumed this has to do with AngularJS sanitizing the string and taking out the javascript. After some googling I tried the following:
$scope.warning = $sce.trustAsJS("alert('This is a warning');");
I also tried trustAsHtml and added the script tags in the string, but neither displayed the alertbox. Could someone tell me and tell me what is going wrong?
it should actually be like this:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.name = 'Superhero';
if ($scope.name==='Superhero') {
alert("hello");
}
}
if you want the alert to be shown conditionally by a changing model on view try something like this:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.name = 'Superhero';
$scope.$watch('name', function(newVal, oldVal) {
alert("hello");
})
}
now every time you will change the 'name' model in your view, the alert will pop-up
refer to the doc for more information about watches
You want $scope.warning to be a function, not the result of the execution of one nor a string.
$scope.warning = function () { alert('This is a warning'); };
That way it can be called later in your view : warning() should display the alert.
Alternatively, since alert is a function, you may just want to use it as $scope.warning :
$scope.warning = alert;
+
warning('this is a warning')
will produce the same result.

Categories