Change the url without reloading the controller in Angularjs - angularjs

Initially, I am showing all the users name in the table. Once the user selected any one of the name, I call the LoadData method with the selected user as the parameter. I am changing the url #/Trades/User/User1 and append the details under the User1. My requirement is 1) In the LoadData method, I want to change the url to as #/Trades/User/User1 or #/Trades/User/User2 based on the selection 2) It should update the data and reflect in view, but it should not reload the controller.
HTML
<div ng-app="myApp" ng-controller="myCtrl">
<table>
<tr ng-repeat-start="val in data.Titles" class="h" ng-click="LoadData(val.title)">
<td colspan="2" ng-hide="val.title == undefined">{{val.title}}</td>
</tr>
<tr ng-repeat="con in val.details">
<td>{{con.portfolio}}</td>
<td>{{con.status}}</td>
</tr>
<tr ng-repeat-end>
<td colspan="2">Load More</td>
</tr>
</table>
</div>
Code
angular.module("myApp", [])
.controller("myCtrl", ["$scope", function ($scope) {
$scope.data = {"Titles":[{title:"User 1",
details: [{portfolio: "Microsoft", status:"Active"},{portfolio:"IBM", status:"Inactive"}]
}, {title:"User 2",
details: [{portfolio: "Yahoo", status:"Inactive"},{portfolio: "Google", status:"Active"}]
}]};
$scope.LoadData = function(id) {
Change the url as #/Trades/Author/User1
Load the details of the User1
};
});

You could try this. I am using this currently in my project for something very similar. http://joelsaupe.com/programming/angularjs-change-path-without-reloading/
app.run(['$route', '$rootScope', '$location', function ($route, $rootScope, $location) {
var original = $location.path;
$location.path = function (path, reload) {
if (reload === false) {
var lastRoute = $route.current;
var un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
un();
});
}
return original.apply($location, [path]);
};
}])

Related

Can't access $scope variables after changing view with $location.path

I'm trying to access data that is on the $scope on a view where the app lands after clicking a button but it seems as if after using $location.path(url) to do the redirection the APP cannot see a variable that exists on the $scope anymore.
Form with the button:
<form ng-submit="getBrokenProbes()">
<table class="table table-striped">
<tr>
<th>Bmonitor</th>
<th>Select Bmonitor</th>
</tr>
<tr ng-repeat="bmonitor in bmonitors">
<td>
<span>{{bmonitor.domainName}}</span>
</td>
<td>
<button class="btn btn-primary" ng-click="getBrokenProbes(bmonitor)">Request</button>
</td>
</tr>
</table>
</form>
Controller:
app.controller('logmeinValidationCtrl', ['$scope','$http', '$location', function($scope,$http, $location){
$scope.bmonitors = {};
$scope.brokenProbes = {};
$http.get('http://localhost/getBmonitors').success(function (data) {
$scope.bmonitors = data;
console.log($scope.bmonitors);
});
$scope.getBrokenProbes = function(bmonitor) {
let url = 'http://localhost/getBrokenProbes';
$http.post(url, bmonitor).then(function (response) {
$scope.brokenProbes = response.data.hosts;
console.log($scope.brokenProbes);
$scope.showBrokenProbes();
})
};
$scope.showBrokenProbes = function () {
$location.path('/logmeinValidationResult')
}
}]);
I'm trying to show that data in a different view but $scope.brokenProbes is not available in logmeinValidationResult.html (the page where I land after $location.path) so it just shows an empty table.
logmeinValidationResult.html
<table class="table table-striped">
<tr>
<th>Probe name</th>
</tr>
<tr ng-repeat="probe in brokenProbes">
<td>
<span>{{probe.description}}</span>
</td>
</tr>
</table>
New page controller:
app.controller('logmeinValidationResultCtrl', ['$scope', function($scope){
console.log($scope.brokenProbes); //This yields undefined
}]);
I) The variable $scope.brokenProbes belongs to the controller logmeinValidationCtrl where is defined...
In order to use it inside another controller, you should pass it - broadcast.
OR
II) Another (Better) solution is when the user gets redirected to logmeinValidationResult, you can call the API, get the data and assign to $scope.brokenProbes variable.
In that case,
your old controller should look like this:
app.controller('logmeinValidationCtrl', ['$scope','$http', '$location', function($scope,$http, $location){
$scope.bmonitors = {};
$http.get('http://localhost/getBmonitors').success(function (data) {
$scope.bmonitors = data;
console.log($scope.bmonitors);
});
$scope.getBrokenProbes = function(bmonitor) {
$location.path('/logmeinValidationResult/' + bmonitor); // Pass bmonitor to the result here so you can call the api with that parameter later on
};
}]);
And your here is how your new page controller should look like:
app.controller('logmeinValidationResultCtrl', ['$scope','$http', '$routeParams', function($scope,$http, $routeParams){
$scope.brokenProbes = [];
let url = 'http://localhost/getBrokenProbes';
let bmonitor = $routeParams.bmonitor; // Get passed bmonitor value from the route params
$http.post(url, bmonitor).then(function (response) {
$scope.brokenProbes = response.data.hosts;
console.log($scope.brokenProbes);
})
}]);
And don't forget to register route param bmonitor to your $routeProvider or whatever you use...

Binding scope object to factory object

I am connecting to a websocket feed in a factory, which gives me real time bitcoin price data.
I define service.prices as an object in websocketFactory, and set wsvm.prices = websocketFactory.prices in the controller.
The wsvm.prices.btc property is not updating in the view, but is logging correctly in console.
code:
factory
app.factory('websocketFactory', ['$http', function($http) {
var service = {}
service.prices = {
"btc": 0
}
service.gdax = function() {
const socket = new WebSocket('wss://ws-feed.gdax.com')
var message = {
"type": "subscribe",
"channels": [{
"name": "ticker",
"product_ids": [
"BTC-USD"
]
}, ]
}
socket.addEventListener('open', function(event) {
socket.send(JSON.stringify(message));
})
// Listen for messages
socket.addEventListener('message', function(event) {
var dataObj = JSON.parse(event.data)
if (dataObj.price) {
console.log(dataObj.price) //logging real time data
service.prices.btc = dataObj.price //this should be updating the view
}
});
}
return service
}])
controller
app.controller('WebsocketController', WebsocketController)
WebsocketController.$inject = ['$scope', 'websocketFactory']
function WebsocketController($scope, websocketFactory) {
var wsvm = this
wsvm.prices = websocketFactory.prices
websocketFactory.gdax()
}
view
<div ng-controller="PortfolioController as vm">
<div class="row">
<div class="col-sm-6">
<h2 style="text-align: center;">Account Balances</h2>
</div>
<div class="col-sm-6">
<table class="table">
<thead>
<tr>
<td>24h Change</td>
<td>Total Val USD</td>
<td>BTC Price</td>
</tr>
</thead>
<tbody>
<tr>
<td ng-class="{change_loss: vm.totals.change_24h_usd < 0, change_win: vm.totals.change_24h_usd > 0}"><b>{{vm.totals.change_24h_usd | currency}}</b></td>
<td><b>{{vm.totals.total_usd | currency}}</b></td>
<td ng-controller="WebsocketController as wsvm">{{wsvm.prices.btc}}</td>
</tr>
</tbody>
</table>
</div>
</div>
How to correctly bind factory to controller for real time data?
Changing scope in the socket listener is outside of angular context. Whenever that happens angular needs to be notified to run a digest to update view
Try the following:
app.factory('websocketFactory', ['$http', '$rootScope', function($http, $rootScope) {
......
socket.addEventListener('message', function(event) {
var dataObj = JSON.parse(event.data)
if (dataObj.price) {
console.log(dataObj.price) //logging real time data
$rootScope.$apply(function(){
service.prices.btc = dataObj.price //this should be updating the view
});
}
});
});
I also suggest you look for an angular socket module that will take care of all of this for you internally

Passing values from controller to controller in AngularJs using Factory

I trying to pass a value from controller1 to controller2 using factory on ng-click, now i have added routing
var app = angular.module("myApp", ['ui.router']);
app.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('ShowData', {
url: '/ShowData',
templateUrl: '../Pages/Show.html'
})
.state('EditData', {
url: '/EditData',
controller:'Editctrl',
templateUrl: '../Pages/Edit.html'
})
});
app.controller('Controller1', function ($scope, $http, Phyfactory) {
//Here I am calling a factory
$scope.open = function (name) {
var message = name;
console.log('Hcpname', message);
Phyfactory.set(message);
$location.url('/EditData');
// this is my second controller
app.controller('Editctrl', function ($scope, Phyfactory) {
alert('cntrl2');
$scope.fks = Phyfactory.get();
});
I want to bind this value to textbox
<div ng-controller="Controller2">
Name: <input type="text" ng-model="fks" />
</div>
//this is my factory
app.factory("Phyfactory", function () {
var phyname = {};
function set(data) {
phyname = data;
alert('Inside set :' + phyname);
}
function get() {
alert('Inside get :' + Object.values(phyname));
return phyname;
}
return {
set: set,get:get
}
})
Adding HTML part for controller1 as requested, i am calling ng-click inside td
<div ng-app="myApp" ng-controller="controller1"
<table class="wtable">
<tr>
<th class="wth">
A
</th>
<th class="wth">
B
</th>
</tr>
<tr ng-repeat="tab in Phyperform | filter:search.view_nm|filter:search.time_period|filter:search.team_nm">
<td class="wtd" ><a ng-click="open(tab.A)"> {{tab.A}} </a> </td>
<td class="wtd"> {{tab.B}} </td>
</tr>
</table>
Value is not passing to controller2 and not redirecting as well.
Any idea?
window.location.href
will redirect to out of the app, you must use routing with $location.
of course a better way to pass data between controllers is using event!
using event like below :
this is event receiver in controller 2:
$scope.$on('myCustomEvent', function (event, data) {
console.log(data); // 'Data to send'
});
and this is the sender event in controller 1:
$scope.$emit('myCustomEvent', 'Data to send');
Credit goes to this post "Sharing Data between pages in AngularJS returning empty"
I able to do using sessionStorage.

Angular Delete row from table using angular services

I am trying to delete a table row using angular services, but unfortunately I don't know how to do that. I have to do that using services because I am using several services with the same control.
<script>
var myApp = angular.module("myApp", []);
myApp.service('allCurrentSettingsService', ['$http', '$q', function ($http, $q) {
var allSettings = null;
this.getList = function () {
var def = $q.defer()
if (allSettings) {
def.resolve(allSettings);
} else {
$http.post('GetAllCurrentSettings')
.then(function (response) {
var response = $.parseJSON(response.data)
allSettings = response;
def.resolve(allSettings);
});
}
return def.promise;
}
}]);
myApp.controller('myController', ['$scope', 'allCurrentSettingsService',
function ($scope, allCurrentSettingsService) {
$scope.allSettings = '';
allCurrentSettingsService.getList().then(function (value) {
$scope.allSettings = value;
});
}
]);
</script>'
And this is my HTML:
`
<div ng-controller="myController">
<table border="1">
<tr ng-repeat="setting in allSettings">
<td><input id="Button1" type="button" value="Delete" data-ng-click="DeleteRow(rowValue)" /></td>
<td class="hidden">{{setting.SettingID}}</td>
<td>{{setting.CompanyName}}</td>
<td>{{setting.CustomerName}}</td>
<td>{{setting.DocumentName}}</td>
</tr>
</table>
</div>
`
Delete method from controller:
[HttpPost]
public static void DeleteRecord(int settingID)
{
try
{
using (SqlConnection conn = new SqlConnection(connStringApps))
{
conn.Open();
using (SqlCommand command = new SqlCommand("DeleteCurrentRecord", conn))
{
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.Add("#SettingId", SqlDbType.VarChar).Value = settingID;
command.ExecuteNonQuery();
command.Parameters.Clear();
}
conn.Close();
}
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
}
Answer Updated
I do not recommend to remove a row from your service, it's better if you do that from controller, but for figure out how can remove a row from service see the example.
To Remove From Controller you just convert the service codes as controller like what you see in sample.
var app = angular.module("app", []);
app.controller("ctrl", function ($scope, service) {
$scope.data = [
{ name: "a" },
{ name: "b" }
];
$scope.deleteRow = function (row) {
$scope.data = service.removeRow(row, $scope.data);
}
$scope.deleteFromController = function (row) {
var indexOf = $scope.data.indexOf(row);
$scope.data.splice(indexOf, 1);
}
});
app.service("service", function ($rootScope) {
this.removeRow = function (row, data) {
var indexOf = data.indexOf(row);
data.splice(indexOf, 1);
return data;
}
});
<!DOCTYPE html>
<html ng-app="app" ng-controller="ctrl">
<head>
<title></title>
</head>
<body>
<h5>click on rows: delete from service</h5>
<table>
<tr ng-repeat="row in data" ng-click="deleteRow(row)">
<td>{{row.name}}</td>
</tr>
</table>
<h5>click on rows: delete from controller</h5>
<table>
<tr ng-repeat="row in data" ng-click="deleteFromController(row)">
<td>{{row.name}}</td>
</tr>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</body>
</html>
From the front end if you want to remove get the index of setting which you want to remove and then use splice.
in the html there has to be an button which initiate the delete operation
your html should be, a rough idea
<tr ng-repeat ="setting in allSettings">
<td>{{setting.SettingID}}</td>
<!-- other items which you wnted to display-->
<!-- put one button for delete and use $index to track the index of item to be removed-->
<td><button ng-click="removeRow($index)">Remove Row</button></td>
</tr>
your controller>>
$scope.removeRoe = function(index){
//splice will remove the setting row and it will get reflected n the view
$scope.allSettings.splice(index,1);
}
FYI
You need not use service, the removing part has to be done in controller. If you need to hit a backend service(post or delete request) that removes the setting then you need to use angular service

How to implement Infinite Scrolling for AngularJS & MVC

I created one angular JS application using MVC 4
where i created one view which renders templates in that we have one template which contains large amount of data as one lack records for that i am looking to implement Infinite Scrolling
1.index.cshtml
<div id="sidebar-left" class="span2">
<div class="nav-collapse sidebar-nav">
<ul class="nav nav-tabs nav-stacked main-menu">
<li class="navbar-brand">Talks</li>
<li class="navbar-brand">SRDNames</li>
<li class="navbar-brand">Speakers</li>
<li class="navbar-brand">Add Talk</li>
</ul>
</div>
</div>
SRDNames.cshtml
<div class="box-content">
<table class="table table-striped table-bordered bootstrap-datatable datatable">
<tr>
<th>
SRD_NAME
</th>
<th>
CREATED_BY_USER_ID
</th>
</tr>
<tr ng-repeat="srdname in srdnames">
<td>
{{srdname.sRD_NAME}}
</td>
<td>
{{srdname.cREATED_BY_USER_ID}}
</td>
</tr>
</table>
3.eventModule.js
var eventModule = angular.module("eventModule", []).config(function ($routeProvider, $locationProvider) {
//Path - it should be same as href link
$routeProvider.when('/Events/Talks', { templateUrl: '/Templates/Talk.html', controller: 'eventController' });
$routeProvider.when('/Events/Speakers', { templateUrl: '/Templates/Speaker.html', controller: 'speakerController' });
$routeProvider.when('/Events/AddTalk', { templateUrl: '/Templates/AddTalk.html', controller: 'talkController' });
$routeProvider.when('/Events/SRDNames', { templateUrl: '/Templates/SRDNames.html', controller: 'srdnamescontroller' });
$locationProvider.html5Mode(true);
});
srdnamescontroller.js
eventModule.controller("srdnamescontroller", function ($scope, EventsService) {
EventsService.getSRDName().then(function (srdnames) { $scope.srdnames = srdnames }, function ()
{ alert('error while fetching talks from server') })
});
5.EventsService.js
eventModule.factory("EventsService", function ($http, $q) {
return {
getSRDName: function () {
// Get the deferred object
var deferred = $q.defer();
// Initiates the AJAX call
$http({ method: 'GET', url: '/events/GetSRDName' }).success(deferred.resolve).error(deferred.reject);
// Returns the promise - Contains result once request completes
return deferred.promise;
},
});
looking to implement like http://jsfiddle.net/vojtajina/U7Bz9/ in above application.. please help
Demo
There are many possible solutions. Here is one that may work for you.
Implement a scroll module that defines the following:
An infiniteScroll directive
A data service to get the scrollable data
You can use the scroll module from within your app:
HTML:
<div ng-app="app" ng-controller="ctrl">
<div infinite-scroll="items">
</div>
</div>
JS:
var app = angular.module('app', ['scroll']);
app.controller('ctrl', function($scope, dataService) {
$scope.items = [];
dataService.loadMore($scope.items, function(lastItem) {
var items = [];
var id = lastItem ? lastItem.id : 0;
for (var i = 0; i < 5; i++) {
items.push({id: id + i});
}
return items;
});
});
The dataService exposes a loadMore method that accepts an array, and a callback function to load more data. The above example loads more data by looping through 5 items, and adding to the array. But you can customize this function callback to retrieve data from another service:
var app = angular.module('app', ['scroll']);
app.controller('ctrl', function($scope, $http, dataService) {
$scope.items = [];
dataService.loadMore($scope.items, function(lastItem, done) {
var lastItemId = lastItem ? lastItem.id : '';
$http({ method: 'GET',url:'api/items/' + lastItemId})
.success(function(items) {
done(items);
});
});
});

Resources