Dynamically Update Model From Web Socket - javascript

Update (High Level Idea/Concept)
To summarize I would like values to be dynamically updated in a controller which is binded to a Web Socket Service, which value change. Below is my attempt of how to solve the problem and the barrier which I am facing.
I would like to update the view model in the controller, each time that the socket pushes information in the service. To mimic the pushing of messages I am just calling a timeout every second, which in turn increase the value of health within the service, which I verified it works in console.
Though the value of the health within controller is never updated, and I am at a loss of of what I am doing wrong. Below are the snippets of relatable code.
This is the controller
(function () {
'use strict';
angular
.module('xxx')
.controller('DashboardController', ['$scope','$timeout', "$uibModal", "dashboardService", "syncService", DashboardController]);
function DashboardController($scope, $timeout, $uibModal, dashboardService, syncService) {
var vm = this;
// VERSIONS
vm.versions = {};
// HEALTH
vm.health= syncService.health;
// JUMP-START
activate();
//////////////
function activate(){
getVersions();
}
function getVersions(){
dashboardService.getVersions()
.then(function(data) {
vm.versions = data;
return vm.versions;
});
}
}
})();
This is the service
(function () {
'use strict';
angular
.module('xxx')
.service('syncService',['$timeout', syncService]);
function syncService($timeout) {
//Init WebSocket
var self = this;
self.health= 0;
updatedStatus();
///////////
....
function updatedStatus(){
$timeout(updatedStatus, 1000);
self.health += 1;
$timeout(angular.noop);
};
}
})();
Update
I would like to know how to make it work without using $scope. Example like in the accepted answer in the following question
thank you

AFAIK, you'll need to put a watch on the service variable. This is what I did to get this to work:
function DashboardController($scope, $timeout, $uibModal, dashboardService, syncService) {
var vm = this;
// VERSIONS
vm.versions = {};
// HEALTH
vm.syncService = syncService;
$scope.$watch('vm.syncService.health', function(newHealth, oldHealth){
vm.health = newHealth;
})
// JUMP-START
activate();
//////////////
function activate(){
getVersions();
}
function getVersions(){
dashboardService.getVersions()
.then(function(data) {
vm.versions = data;
return vm.versions;
});
}
}
I linked a similar question in the comments and in the answers they also talk about using $broadcast if you need more than one controller to be aware of any changes to the variable's value in your service.

Related

Properly using an Angular MVC setup

Feel free to clear up any misunderstandings you see here; I'm not a front end guy.
Now, I've read that much of the logic shouldn't exist in the controller, and that it should be put somewhere else. But most places I look that show code don't specify which file it belongs in. On this project that I've inherited I have 4 files that deal with the main functionality:
A controller - autoDeploy.js
A service - autoDeploy.service.js
A module - autoDeploy.module.js
Directives - directives.js
directives.js just contains the templates that I want to inject into the DOM upon the click of a button, the directives will be referenced later.
autoDeploy.module.js does all of the module.config and $stateProvider routing stuff; I don't touch it beyond my initial modification to point to the new page I'm making so it can be properly routed to.
autoDeploy.service.js: In the examples I've seen, the .factory()'s (or .service()) last parameter usually opens up as a function, and all of the functionality in the file happens inside there. Mine isn't like that, it's an iife with the factory being a standalone command followed by what looks like a constructor. Here's what I have:
(function () { //start iife
'use strict';
angular.module('gms.autoDeploy')
.factory('AutoDeployService', ["$http", "$q", "$log", "$cookies", "APP_CONFIGS", "SweetAlert", "$timeout", "GridSettingsService", "APP_USER", AutoDeployService]);
function AutoDeployService($http, $q, $log, $cookies, APP_CONFIGS, $timeout, SweetAlert, GridSettingsService, APP_USER) {
//return service object at bottom of function
function returnOne() {
return "one";
}
var service = {
returnOne: returnOne
};
return service;
} //end AutoDeployService
}()); //end iife
Why did the original developer...
Use as an iife?
Return the service variable after making it a function mapping?
Put all of the functionality in the constructor like function?
My guess to the above 2nd and 3rd answers is that it is the constructor for the service and the controller can some how know it's a usable object because we pass it in as a parameter to the controller as you can see on the top line of the code below. I also don't know much about the parameters for the "constructor", but I can look those up later.
Now for the controller. Unlike the service above, the controller declaration does open up as a function in the parameters of .controller() as I've seen other places. Here it is, simplified (methods with similar functionality are cut out):
angular.module("gms.autoDeploy").controller('AutoDeployController', ['$scope', '$compile', 'AutoDeployService',
function ($scope, $compile, AutoDeployService) {
var vm = this;
init();
function init() {
vm.isInstantiated = true;
vm.data = {
"parameter": []
};
}
// calling a function from the service to show that we can pass
// data from controller to service
vm.change = function () {
vm.message = AutoDeployService.returnOne("not one");
};
//function assigned to button click on the DOM allowing
// the directive to inject the template where the <tib-copy> tag is
vm.addCopy = function (ev, attrs) {
var copy = angular.element(document.createElement('copy'));
var el = $compile(copy)(vm);
angular.element(document.getElementsByTagName("tib-copy")).append(copy);
vm.insertHere = el;
};
// This method extracts data from the following fields dynamically added by the click of a button:
// - TIBCO Server(s)
// - TIBCO Domain(s)
// - TIBCO Application(s)
vm.getTibPromotionData = function () {
// Add all TIBCO servers
var servers = document.getElementsByName("tibServer");
var tibSvrList = [];
for (var i = 0; i < servers.length; i++) {
tibSvrList.push(servers[i].value);
}
// Add all TIBCO domains
var domains = document.getElementsByName("tibDomain");
var tibDomainList = [];
for (i = 0; i < domains.length; i++) {
tibDomainList.push(domains[i].value);
}
// Add all applications
var tibApps = document.getElementsByName("tibApp");
var tibAppList = [];
for (i = 0; i < tibApps.length; i++) {
tibAppList.push(tibApps[i].value);
}
// Add the processed data to the final JSON
vm.data.parameter.push({
"name": "TIBCO_Promotion",
"value": JSON.stringify("[{\"server\":[" + tibSvrList + "]},{\"domain\":[" + tibDomainList + "]},{\"application\":[" + tibAppList + "]}]")
});
};
}
]);
Please, let me know if you see anything in the controller that should belong in the autoDeploy.service.js file. Furthermore, if anyone has experience with this file naming convention, I'd love to hear an explanation as to why there are files named *.service.js and *.module.js, and if the *.service.js file has anything to do with the concept of services and factories, or if it's intended to be conceptual, as if it's just a reference to being the back end services component.

AngularJS automatically updating controller data by service

I'm having some basic problems with angular at the moment. I just wrote a service that reads the temperature of an external device in an interval of five seconds. The service saves the new temperature into a variable and exposes it via a return statement. This looks kind of this (simplified code):
angular.service("tempService", ["$interval", function ($interval) {
//revealing module pattern
var m_temp = 0,
requestTemp = function() {//some logic here},
onResponseTemp = function (temp) {
m_temp = temp;
},
//some other private functions and vars ...
foo = bar;
//request new temperture every 5s, calls onResponseTemp after new data got received
$interval(requestTemp, 5000);
return {
getTemp = function(){return m_temp;}
}
}]);
I use a controller to fetch the data from the service like this:
angular.controller("tempCtrl", ["$scope", "tempService", function ($scope, tempService) {
$scope.temp = tempService.getTemp();
}]);
In my view I access it like this:
<div ng-controller="tempCtrl">
<p>{{temp}}</p>
</div>
But I only get 0 and the value never changes. I have tried to implement a custom Pub/Sub pattern so that on a new temperature my service fires an event that my controller is waiting for to update the temperature on the scope. This approach works just fine but I'm not sure if this is the way to go as angular brings data-binding and I thought something this easy had to work by itself ;)
Help is really appreciated.
Please see here http://jsbin.com/wesucefofuyo/1/edit
var app = angular.module('app',[]);
app.service("tempService", ["$interval", function ($interval) {
//revealing module pattern
var m_temp = {
temp:0,
time:null
};
var requestTemp = function() {
m_temp.temp++;
m_temp.time = new Date();
};
var startTemp = function() {
$interval(requestTemp, 3000);
};
return {
startTemp :startTemp,
m_temp:m_temp
};
}]);
app.controller('fCtrl', function($scope,tempService){
$scope.temp = tempService;
$scope.temp.startTemp();
});
You are returning a primitive from your service, if you want to update an primative you need to reftech it. You should return an object, as on object is passed by reference, you get the actual values in your controller.
do this in your service:
return m_temp;
And this in your controller:
$scope.temp = tempService;
and your view will update as soon as the service gets updated.
Does this help you?
i think you should use $interval in controller ot in service
$interval(tempService.getTemp(), 5000);

How to include/inject functions which use $scope into a controller in angularjs?

I am trying to include a library of functions, held in a factory, into a controller.
Similar to questions like this:
Creating common controller functions
My main controller looks like this:
recipeApp.controller('recipeController', function ($scope, groceryInterface, ...){
$scope.groceryList = [];
// ...etc...
/* trying to retrieve the functions here */
$scope.groceryFunc = groceryInterface; // would call ng-click="groceryFunc.addToList()" in main view
/* Also tried this:
$scope.addToList = groceryInterface.addToList();
$scope.clearList = groceryInterface.clearList();
$scope.add = groceryInterface.add();
$scope.addUp = groceryInterface.addUp(); */
}
Then, in another .js file, I have created the factory groceryInterface. I've injected this factory into the controller above.
Factory
recipeApp.factory('groceryInterface', function(){
var factory = {};
factory.addToList = function(recipe){
$scope.groceryList.push(recipe);
... etc....
}
factory.clearList = function() {
var last = $scope.prevIngredients.pop();
.... etc...
}
factory.add = function() {
$scope.ingredientsList[0].amount = $scope.ingredientsList[0].amount + 5;
}
factory.addUp = function(){
etc...
}
return factory;
});
But in my console I keep getting ReferenceError: $scope is not defined
at Object.factory.addToList, etc. Obviously I'm guessing this has to do with the fact that I'm using $scope in my functions within the factory. How do I resolve this? I notice that in many other examples I've looked at, nobody ever uses $scope within their external factory functions. I've tried injecting $scope as a parameter in my factory, but that plain out did not work. (e.g. recipeApp.factory('groceryInterface', function(){ )
Any help is truly appreciated!
Your factory can't access your $scope, since it's not in the same scope.
Try this instead:
recipeApp.controller('recipeController', function ($scope, groceryInterface) {
$scope.addToList = groceryInterface.addToList;
$scope.clearList = groceryInterface.clearList;
$scope.add = groceryInterface.add;
$scope.addUp = groceryInterface.addUp;
}
recipeApp.factory('groceryInterface', function () {
var factory = {};
factory.addToList = function (recipe) {
this.groceryList.push(recipe);
}
factory.clearList = function() {
var last = this.prevIngredients.pop();
}
});
Alternatively, you can try using a more object oriented approach:
recipeApp.controller('recipeController', function ($scope, groceryInterface) {
$scope.groceryFunc = new groceryInterface($scope);
}
recipeApp.factory('groceryInterface', function () {
function Factory ($scope) {
this.$scope = $scope;
}
Factory.prototype.addToList = function (recipe) {
this.$scope.groceryList.push(recipe);
}
Factory.prototype.clearList = function() {
var last = this.$scope.prevIngredients.pop();
}
return Factory;
});
You cannot use $scope in a factory as it is not defined. Instead, in your factory functions change the properties of the object the factory is returning, e.g.
factory.addToList = function (recipe) {
this.groceryList.push(recipe);
}
these will then get passed on to your $scope variable
$scope.addToList = groceryInterface.addToList;
// ... = groceryInterface.addToList(); would assign to `$scope.addToList` what is returned, instead of the function itself.
This isn't the exact answer for this question, but I had a similar issues that I solved by simply passing $scope as an argument to a function in my factory. So it won't be the normal $scope, but $scope at the time the function in the factory is called.
app.controller('AppController', function($scope, AppService) {
$scope.getList = function(){
$scope.url = '/someurl'
// call to service to make rest api call to get data
AppService.getList($scope).then(function(res) {
// do some stuff
});
}
});
app.factory('AppService', function($http, $q){
var AppService = {
getList: function($scope){
return $http.get($scope.url).then(function(res){
return res;
});
},
}
return AppService;
});

Is this a good way to keep data in sync between two controllers?

I have got a page layout with two controllers at the same time, one holds the data displayed as kind of side navigation, based on data stored the browsers local storage and at least one other controller, which is bind to a route and view.
I created this little wire frame graphic below which show the page layout:
The second controller is used for manipulating the local stored data and performs actions like adding a new item or deleting an existing one. My goal is to keep the data in sync, if an item got added or deleted by the 'ManageListCrtl' the side navigation using the 'ListCtrl' should get updated immediately.
I archived this by separating the local storage logic into a service which performs a broadcast when the list got manipulated, each controller listens on this event and updates the scope's list.
This works fine, but I'm not sure if there is the best practice.
Here is a stripped down version of my code containing just the necessary parts:
angular.module('StoredListExample', ['LocalObjectStorage'])
.service('StoredList', function ($rootScope, LocalObjectStorage) {
this.add = function (url, title) {
// local storage add logic
$rootScope.$broadcast('StoredList', list);
};
this.delete = function (id) {
// local storage delete logic
$rootScope.$broadcast('StoredList', list);
};
this.get = function () {
// local storage get logic
};
});
angular.module('StoredListExample')
.controller('ListCtrl', function ($scope, StoredList) {
$scope.list = StoredList.get();
$scope.$on('StoredList', function (event, data) {
$scope.list = data;
});
});
angular.module('StoredListExample')
.controller('ManageListCtrl', function ($scope, $location, StoredList) {
$scope.list = StoredList.get();
$scope.add = function () {
StoredList.add($scope.url, $scope.title);
$location.path('/manage');
};
$scope.delete = function (id) {
StoredList.delete(id);
};
$scope.$on('StoredList', function (event, data) {
$scope.list = data;
});
});
I don't see anything wrong with doing it this way. Your other option of course is to just inject $rootScope into both controllers and pub/sub between them with a $rootScope.$broadcast and a $rootScope.$on.
angular.module('StoredListExample')
.controller('ListCtrl', function ($scope, $rootScope) {
$scope.list = [];
$rootScope.$on('StoredList', function (event, data) {
$scope.list = data;
});
});
angular.module('StoredListExample')
.controller('ManageListCtrl', function ($scope, $rootScope, $location) {
$scope.list = [];
$scope.add = function () {
//psuedo, not sure if this is what you'd be doing...
$scope.list.push({ url: $scope.url, title: $scope.title});
$scope.storedListUpdated();
$location.path('/manage');
};
$scope.delete = function (id) {
var index = $scope.list.indexOf(id);
$scope.list.splice(index, 1);
$scope.storedListUpdated();
};
$scope.storedListUpdated = function () {
$rootScope.$broadcast('StoredList', $scope.list);
};
});
Additionally, you can achieve this in a messy but fun way by having a common parent controller. Whereby you would $emit up a 'StoredListUpdated' event from 'ManageListCtrl' to the parent controller, then the parent controller would $broadcast the same event down to the 'ListCtrl'. This would allow you to avoid using $rootScope, but it would get pretty messy in terms of readability as you add more events in this way.
It is always a better practice to use a common service that is a singleton for sharing the data between the 2 controllers - just make sure you use only references and not creating a local object in one of the controllers that should actually be in the service

Maintain model of scope when changing between views in AngularJS

I am learning AngularJS. Let's say I have /view1 using My1Ctrl, and /view2 using My2Ctrl; that can be navigated to using tabs where each view has its own simple, but different form.
How would I make sure that the values entered in the form of view1 are not reset, when a user leaves and then returns to view1 ?
What I mean is, how can the second visit to view1 keep the exact same state of the model as I left it ?
I took a bit of time to work out what is the best way of doing this. I also wanted to keep the state, when the user leaves the page and then presses the back button, to get back to the old page; and not just put all my data into the rootscope.
The final result is to have a service for each controller. In the controller, you just have functions and variables that you dont care about, if they are cleared.
The service for the controller is injected by dependency injection. As services are singletons, their data is not destroyed like the data in the controller.
In the service, I have a model. the model ONLY has data - no functions -. That way it can be converted back and forth from JSON to persist it. I used the html5 localstorage for persistence.
Lastly i used window.onbeforeunload and $rootScope.$broadcast('saveState'); to let all the services know that they should save their state, and $rootScope.$broadcast('restoreState') to let them know to restore their state ( used for when the user leaves the page and presses the back button to return to the page respectively).
Example service called userService for my userController :
app.factory('userService', ['$rootScope', function ($rootScope) {
var service = {
model: {
name: '',
email: ''
},
SaveState: function () {
sessionStorage.userService = angular.toJson(service.model);
},
RestoreState: function () {
service.model = angular.fromJson(sessionStorage.userService);
}
}
$rootScope.$on("savestate", service.SaveState);
$rootScope.$on("restorestate", service.RestoreState);
return service;
}]);
userController example
function userCtrl($scope, userService) {
$scope.user = userService;
}
The view then uses binding like this
<h1>{{user.model.name}}</h1>
And in the app module, within the run function i handle the broadcasting of the saveState and restoreState
$rootScope.$on("$routeChangeStart", function (event, next, current) {
if (sessionStorage.restorestate == "true") {
$rootScope.$broadcast('restorestate'); //let everything know we need to restore state
sessionStorage.restorestate = false;
}
});
//let everthing know that we need to save state now.
window.onbeforeunload = function (event) {
$rootScope.$broadcast('savestate');
};
As i mentioned this took a while to come to this point. It is a very clean way of doing it, but it is a fair bit of engineering to do something that i would suspect is a very common issue when developing in Angular.
I would love to see easier, but as clean ways to handle keeping state across controllers, including when the user leaves and returns to the page.
A bit late for an answer but just updated fiddle with some best practice
jsfiddle
var myApp = angular.module('myApp',[]);
myApp.factory('UserService', function() {
var userService = {};
userService.name = "HI Atul";
userService.ChangeName = function (value) {
userService.name = value;
};
return userService;
});
function MyCtrl($scope, UserService) {
$scope.name = UserService.name;
$scope.updatedname="";
$scope.changeName=function(data){
$scope.updateServiceName(data);
}
$scope.updateServiceName = function(name){
UserService.ChangeName(name);
$scope.name = UserService.name;
}
}
$rootScope is a big global variable, which is fine for one-off things, or small apps.
Use a service if you want to encapsulate your model and/or behavior (and possibly reuse it elsewhere). In addition to the google group post the OP mentioned, see also https://groups.google.com/d/topic/angular/eegk_lB6kVs/discussion.
Angular doesn't really provide what you are looking for out of the box. What i would do to accomplish what you're after is use the following add ons
UI Router & UI Router Extras
These two will provide you with state based routing and sticky states, you can tab between states and all information will be saved as the scope "stays alive" so to speak.
Check the documentation on both as it's pretty straight forward, ui router extras also has a good demonstration of how sticky states works.
I had the same problem, This is what I did:
I have a SPA with multiple views in the same page (without ajax), so this is the code of the module:
var app = angular.module('otisApp', ['chieffancypants.loadingBar', 'ngRoute']);
app.config(['$routeProvider', function($routeProvider){
$routeProvider.when('/:page', {
templateUrl: function(page){return page.page + '.html';},
controller:'otisCtrl'
})
.otherwise({redirectTo:'/otis'});
}]);
I have only one controller for all views, but, the problem is the same as the question, the controller always refresh data, in order to avoid this behavior I did what people suggest above and I created a service for that purpose, then pass it to the controller as follows:
app.factory('otisService', function($http){
var service = {
answers:[],
...
}
return service;
});
app.controller('otisCtrl', ['$scope', '$window', 'otisService', '$routeParams',
function($scope, $window, otisService, $routeParams){
$scope.message = "Hello from page: " + $routeParams.page;
$scope.update = function(answer){
otisService.answers.push(answers);
};
...
}]);
Now I can call the update function from any of my views, pass values and update my model, I haven't no needed to use html5 apis for persistence data (this is in my case, maybe in other cases would be necessary to use html5 apis like localstorage and other stuff).
An alternative to services is to use the value store.
In the base of my app I added this
var agentApp = angular.module('rbAgent', ['ui.router', 'rbApp.tryGoal', 'rbApp.tryGoal.service', 'ui.bootstrap']);
agentApp.value('agentMemory',
{
contextId: '',
sessionId: ''
}
);
...
And then in my controller I just reference the value store. I don't think it holds thing if the user closes the browser.
angular.module('rbAgent')
.controller('AgentGoalListController', ['agentMemory', '$scope', '$rootScope', 'config', '$state', function(agentMemory, $scope, $rootScope, config, $state){
$scope.config = config;
$scope.contextId = agentMemory.contextId;
...
Solution that will work for multiple scopes and multiple variables within those scopes
This service was based off of Anton's answer, but is more extensible and will work across multiple scopes and allows the selection of multiple scope variables in the same scope. It uses the route path to index each scope, and then the scope variable names to index one level deeper.
Create service with this code:
angular.module('restoreScope', []).factory('restoreScope', ['$rootScope', '$route', function ($rootScope, $route) {
var getOrRegisterScopeVariable = function (scope, name, defaultValue, storedScope) {
if (storedScope[name] == null) {
storedScope[name] = defaultValue;
}
scope[name] = storedScope[name];
}
var service = {
GetOrRegisterScopeVariables: function (names, defaultValues) {
var scope = $route.current.locals.$scope;
var storedBaseScope = angular.fromJson(sessionStorage.restoreScope);
if (storedBaseScope == null) {
storedBaseScope = {};
}
// stored scope is indexed by route name
var storedScope = storedBaseScope[$route.current.$$route.originalPath];
if (storedScope == null) {
storedScope = {};
}
if (typeof names === "string") {
getOrRegisterScopeVariable(scope, names, defaultValues, storedScope);
} else if (Array.isArray(names)) {
angular.forEach(names, function (name, i) {
getOrRegisterScopeVariable(scope, name, defaultValues[i], storedScope);
});
} else {
console.error("First argument to GetOrRegisterScopeVariables is not a string or array");
}
// save stored scope back off
storedBaseScope[$route.current.$$route.originalPath] = storedScope;
sessionStorage.restoreScope = angular.toJson(storedBaseScope);
},
SaveState: function () {
// get current scope
var scope = $route.current.locals.$scope;
var storedBaseScope = angular.fromJson(sessionStorage.restoreScope);
// save off scope based on registered indexes
angular.forEach(storedBaseScope[$route.current.$$route.originalPath], function (item, i) {
storedBaseScope[$route.current.$$route.originalPath][i] = scope[i];
});
sessionStorage.restoreScope = angular.toJson(storedBaseScope);
}
}
$rootScope.$on("savestate", service.SaveState);
return service;
}]);
Add this code to your run function in your app module:
$rootScope.$on('$locationChangeStart', function (event, next, current) {
$rootScope.$broadcast('savestate');
});
window.onbeforeunload = function (event) {
$rootScope.$broadcast('savestate');
};
Inject the restoreScope service into your controller (example below):
function My1Ctrl($scope, restoreScope) {
restoreScope.GetOrRegisterScopeVariables([
// scope variable name(s)
'user',
'anotherUser'
],[
// default value(s)
{ name: 'user name', email: 'user#website.com' },
{ name: 'another user name', email: 'anotherUser#website.com' }
]);
}
The above example will initialize $scope.user to the stored value, otherwise will default to the provided value and save that off. If the page is closed, refreshed, or the route is changed, the current values of all registered scope variables will be saved off, and will be restored the next time the route/page is visited.
You can use $locationChangeStart event to store the previous value in $rootScope or in a service. When you come back, just initialize all previously stored values. Here is a quick demo using $rootScope.
var app = angular.module("myApp", ["ngRoute"]);
app.controller("tab1Ctrl", function($scope, $rootScope) {
if ($rootScope.savedScopes) {
for (key in $rootScope.savedScopes) {
$scope[key] = $rootScope.savedScopes[key];
}
}
$scope.$on('$locationChangeStart', function(event, next, current) {
$rootScope.savedScopes = {
name: $scope.name,
age: $scope.age
};
});
});
app.controller("tab2Ctrl", function($scope) {
$scope.language = "English";
});
app.config(function($routeProvider) {
$routeProvider
.when("/", {
template: "<h2>Tab1 content</h2>Name: <input ng-model='name'/><br/><br/>Age: <input type='number' ng-model='age' /><h4 style='color: red'>Fill the details and click on Tab2</h4>",
controller: "tab1Ctrl"
})
.when("/tab2", {
template: "<h2>Tab2 content</h2> My language: {{language}}<h4 style='color: red'>Now go back to Tab1</h4>",
controller: "tab2Ctrl"
});
});
<!DOCTYPE html>
<html>
<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-route.js"></script>
<body ng-app="myApp">
Tab1
Tab2
<div ng-view></div>
</body>
</html>

Categories