How to get contentEditable element's updated value in angular js? - angularjs

var myApp = angular.module("problemApp", []);
myApp.controller("RESTCall", function ($scope, $compile, $element, $timeout) {
$scope.username = 'Adan';
console.log($scope.username)
$scope.printValue = function(data) {
$timeout(function () {
$scope.$apply(function(){
console.log(data);
});
});
}
});
table td, th{
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<div ng-app="problemApp">
<div ng-controller="RESTCall">
<form name="covertToProForm" id=
"table-print">
<table id="confirm">
<tr>
<th>Firstname</th>
<td contentEditable ng-keyup="printValue(username)" ng-model="username">{{username}}</td>
</tr>
<tr>
<th>Lastname</th>
<td>Smith</td>
</tr>
</table>
</form>
</div>
</div>
I have the above table which has a td, that has contentEditable attribute. On editing td's value, I want to print its value in console. Any help would be appreciated!
Edited snippet with the given answer. It's not working.

Please disregard my previous answer. The whole thing is we need to wrap contenteditable in a custom directive because contenteditable directive does not not work directly with angular's ng-model just because it re-render the dom element on every change, resulting in loosing the recent ng-model change.
here's a new wrapper around contenteditable
var app = angular.module('app', []);
app.directive('contenteditable', function() {
return {
restrict: "A",
require: 'ngModel',
controller: function($scope) {
$scope.username = 'Adan';
$scope.printValue = function() {
console.log($scope.username);
}
},
link: function(scope, element, attrs, myController) {
element.on('keyup', function() {
scope.$apply(updateViewModel);
});
function updateViewModel() {
var htmlValue = element.text()
myController.$setViewValue(htmlValue);
scope.printValue();
}
myController.$render = updateHtml
function updateHtml() {
var viewModelValue = myController.$viewValue
element.text(viewModelValue);
}
}
};
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.2.7" data-semver="1.2.7" src="https://code.angularjs.org/1.2.7/angular.js"></script>
<link href="style.css" rel="stylesheet" />
<script src="script.js"></script>
</head>
<body>
<div>
<h2>{{username}}</h2>
<form>
<table>
<tr>
<th>Firstname</th>
<td contenteditable ng-model="username">{{username}}</td>
</tr>
<tr>
<th>Lastname</th>
<td>Smith</td>
</tr>
</table>
</form>
</div>
</body>
</html>

Related

The view page is disabled once the bootstrap modal is closed. (AngularJS)

I have a table of users. When I click on a user name , it has to display a bootstrap modal . But once i close the modal , the table page is locked and I'm not able to click on any other user's name . The page is locked .
The code be like ,
<!DOCTYPE html>
<html>
<head>
<title>TAble</title>
<style>
table, th{
border: 1px solid Green;border-collapse : collapse;
margin:25px;
text-align:center;
}
td {
border: 1px solid Green;
}
th{
padding: 5px;
Font-size:110%;
}
</style>
</head>
<body ng-app="myApp">
<script src="1.4.8/angular.js"></script>
<script src="angular-ui-router.js"></script>
<script src="angular-animate.js"></script>
<script src="ui-bootstrap-tpls-1.3.3.js"></script>
<script src="ng-table.js"></script>
<link rel="stylesheet" href="ng-table.min.css">
<link rel="stylesheet" href="bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<body ng-app="myApp">
<div ng-controller="tableController">
{{test}}
<table ng-table="usersTable" style="width:85%" class="table table-striped">
<tr ng-repeat="x in data" >
<td data-title="'Id'" filter="{ Id: 'number'}">
<a ng-click='open(x)'>{{x.id}}</a>
</td>
<td data-title="'First Name'">
{{x.first_name}}
</td>
<td data-title="'Last Name'">
{{x.last_name}}
</td>
<td data-title="'e-mail'" >
{{x.email}}
</td>
<td data-title="'Country'">
{{x.country}}
</td>
<td data-title="'IP'" >
{{x.ip_address}}
</td>
</tr>
</table>
</div>
</body>
<script>
var app = angular.module('myApp',['ngTable','ui.router','ngAnimate', 'ui.bootstrap']);
app.controller('tableController',function($scope,$uibModal,$filter,ngTableParams)
{
$scope.customers = [{"id":1,"first_name":"Philip","last_name":"Kim","email":"pkim0#mediafire.com","country":"Indonesia","ip_address":"29.107.35.8"},
{"id":2,"first_name":"Judith","last_name":"Austin","email":"jaustin1#mapquest.com","country":"China","ip_address":"173.65.94.30"},
{"id":3,"first_name":"Julie","last_name":"Wells","email":"jwells2#illinois.edu","country":"Finland","ip_address":"9.100.80.145"},
{"id":4,"first_name":"Gloria","last_name":"Greene","email":"ggreene3#blogs.com","country":"Indonesia","ip_address":"69.115.85.157"},
{"id":50,"first_name":"Andrea","last_name":"Greene","email":"agreene4#fda.gov","country":"Russia","ip_address":"128.72.13.52"}];
$scope.usersTable = new ngTableParams({ },
{
getData: function ($defer, params) {
count:[],
$scope.data = params.filter() ? $filter('filter')($scope.customers, params.filter()) : $scope.data;
$defer.resolve($scope.data);
}
});
$scope.localID=0;
$scope.count=2;
$scope.open = function(w) {
var modalInstance = $uibModal.open({
animation: true,
template: '<h1>Hello</h1>',
controller: 'ModalInstanceCtrl',
backdrop:false,
keyboard:true,
size:'Lg',
resolve: {
customers: function () {
return w;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
});
};
});
app.controller('ModalInstanceCtrl', function ($scope, $uibModalInstance,customers) {
$scope.data = customers;
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
});
</script>
</html>
Found the Solution . I was using angularjs1.4.8 so this problem occured ! I tried using AngularJS 1.5.3 and it worked properly !

how to push data to grid in AngularJs

here I created sample program for employee list using wijmo grid, here my problem is i m not able to push the data in gird,
Note: error shows push undefined
Thanks in advance........................................
angular.module('app', ['wj']);
'use strict';
// declare app module
var app = angular.module('app');
// controller
app.controller('appCtrl', function ($scope, $http) {
data = [];
$scope.save=function(reg)
{
var obj = [reg];
$scope.data = new wijmo.collections.CollectionView(obj);
}
// create the filter and expose it to scope for customization
$scope.initialized = function (s, e) {
var flex = s;
$scope.filter = new wijmo.grid.filter.FlexGridFilter(flex);
$scope.downloadsColumnFilterType = wijmo.grid.filter.FilterType.Condition;
$scope.$apply();
$scope.filter.filterChanging.addHandler(function () {
console.log('filter changing');
});
$scope.filter.filterChanged.addHandler(function () {
console.log('filter changed');
});
$scope.filter.filterApplied.addHandler(function () {
console.log('filter applied');
});
}
// filters are localizable
// invalidate all Wijmo controls
// using a separate function to handle strange IE9 scope issues
$scope.data = new wijmo.collections.CollectionView(data);
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css" />
<!-- Wijmo -->
<script src="http://demos.wijmo.com/5/Angular/FlexGridFilter/FlexGridFilter/scripts/vendor/wijmo.min.js" type="text/javascript"></script>
<script src="http://demos.wijmo.com/5/Angular/FlexGridFilter/FlexGridFilter/scripts/vendor/wijmo.grid.min.js" type="text/javascript"></script>
<script src="http://demos.wijmo.com/5/Angular/FlexGridFilter/FlexGridFilter/scripts/vendor/wijmo.grid.filter.min.js" type="text/javascript"></script>
<script src="http://demos.wijmo.com/5/Angular/FlexGridFilter/FlexGridFilter/scripts/vendor/wijmo.input.min.js" type="text/javascript"></script>
<link href="http://demos.wijmo.com/5/Angular/FlexGridFilter/FlexGridFilter/styles/vendor/wijmo.min.css" rel="stylesheet" />
<!-- Wijmo-Angular interop -->
<script src="http://demos.wijmo.com/5/Angular/FlexGridFilter/FlexGridFilter/scripts/vendor/wijmo.angular.min.js" type="text/javascript"></script>
</head>
<body ng-app="app" ng-controller="appCtrl">
<table>
<tr>
<td>First Name</td>
<td>:</td>
<td><input type="text" ng-model="reg.fname"> </td>
</tr>
<tr>
<td>Last Name</td>
<td>:</td>
<td><input type="text" ng-model="reg.lname"> </td>
</tr>
<tr>
<td>Midle Name</td>
<td>:</td>
<td><input type="text" ng-model="reg.mname"> </td>
</tr>
<tr>
<td><input type="submit" ng-click=save(reg)> </td>
</tr>
</table>
<wj-flex-grid
style="height:300px"
initialized="initialized(s, e)"
items-source="data">
<wj-flex-grid-column header="ID" binding="id"></wj-flex-grid-column>
<wj-flex-grid-column header="fname" binding="fname" format='MMM/dd/yyyy'></wj-flex-grid-column>
<wj-flex-grid-column header="lname" binding="lname" format="t"></wj-flex-grid-column>
<wj-flex-grid-column header="mname" binding="mname"></wj-flex-grid-column>
</wj-flex-grid>
</div>
</html>
You should define newItemCreator function, that takes no parameters:
.controller("appCtrl", function ($scope) {
var data = new wijmo.collections.CollectionView([]);
// here
data.newItemCreator = function() {
var item = {};
item = angular.copy($scope.reg);
return item;
};
$scope.data = data;
// create the filter and expose it to scope for customization
$scope.initialized = function (s, e) {
var flex = s;
$scope.filter = new wijmo.grid.filter.FlexGridFilter(flex);
$scope.downloadsColumnFilterType = wijmo.grid.filter.FilterType.Condition;
$scope.$apply();
$scope.filter.filterChanging.addHandler(function () {
console.log('filter changing');
});
$scope.filter.filterChanged.addHandler(function () {
console.log('filter changed');
});
$scope.filter.filterApplied.addHandler(function () {
console.log('filter applied');
});
};
});
And use addNew() method on your button:
<td><button type="button" ng-click=data.addNew()>Save</button></td>

How to do preloader for `ng-view` in Angular JS?

I use <div ng-view></div> on web page.
When I click link in block <div> is loaded HTML template was set in routeProvider. Also together is done request AJAX that returns data that was loaded template.
Now problem is that after click I get HTML template with empty form, still is working AJAX request. After some seconds form HTML is fiiled data from AJAX.
How I can do preloader to page for directory ng-view?
It seems that there are some similar questions here:
Angularjs loading screen on ajax request
Angular JS loading screen and page animation.
Also, there a bunch of modules to work with loading animation at http://ngmodules.org. For example, these:
https://github.com/cgross/angular-busy
https://github.com/chieffancypants/angular-loading-bar (I use this one in my apps)
https://github.com/McNull/angular-block-ui and other.
UPD:
I've written a simple solution based on how the angular-loading-bar works. I didn't test it with ng-view, but it seams to work with ui-view. It is not a final solution and have to be polished.
angular.module('ui')
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('LoadingListener');
}])
.factory('LoadingListener', [ '$q', '$rootScope', function($q, $rootScope) {
var reqsActive = 0;
function onResponse() {
reqsActive--;
if (reqsActive === 0) {
$rootScope.$broadcast('loading:completed');
}
}
return {
'request': function(config) {
if (reqsActive === 0) {
$rootScope.$broadcast('loading:started');
}
reqsActive++;
return config;
},
'response': function(response) {
if (!response || !response.config) {
return response;
}
onResponse();
return response;
},
'responseError': function(rejection) {
if (!rejection || !rejection.config) {
return $q.reject(rejection);
}
onResponse();
return $q.reject(rejection);
},
isLoadingActive : function() {
return reqsActive === 0;
}
};
}])
.directive('loadingListener', [ '$rootScope', 'LoadingListener', function($rootScope, LoadingListener) {
var tpl = '<div class="loading-indicator" style="position: absolute; height: 100%; width: 100%; background-color: #fff; z-index: 1000">Loading...</div>';
return {
restrict: 'CA',
link: function linkFn(scope, elem, attr) {
var indicator = angular.element(tpl);
elem.prepend(indicator);
elem.css('position', 'relative');
if (!LoadingListener.isLoadingActive()) {
indicator.css('display', 'none');
}
$rootScope.$on('loading:started', function () {
indicator.css('display', 'block');
});
$rootScope.$on('loading:completed', function () {
indicator.css('display', 'none');
});
}
};
}]);
It can be used like this:
<section class="content ui-view" loading-listener></section>
You can try something like this(simplest solution):
Set your loader animation/picture:<div class="loader" ng-show="isLoading"></div>
On div element add click event:
Then AJAX request success set isLoading=true
Download javascript and css files from PACE Loader.
Playing around with pace loader using ng-views . Hope this helps someone trying to use PACE.JS with Angular. In this example I am using ng-router to navigate between views.
app.js
var animateApp = angular.module('route-change-loader', ['ngRoute']);
var slowResolve = function(slowDataService){
return slowDataService.getContacts();
};
slowResolve.$inject = ['slowDataService'];
// ROUTING ===============================================
// set our routing for this application
// each route will pull in a different controller
animateApp.config(function($routeProvider) {
$routeProvider
// home page
.when('/route1', {
templateUrl: 'route1.html',
controller: 'slowCtrl',
controllerAs:'ctrl',
resolve: {
contacts:slowResolve
}
})
.otherwise({
templateUrl:'default.html'
});
});
var SlowCtrl = function(contacts) {
this.contacts = contacts;
};
SlowCtrl.$inject = ['contacts'];
angular.extend(SlowCtrl.prototype, {
message:'Look Mom, No Lag!',
contacts: []
});
animateApp.controller('slowCtrl', SlowCtrl);
var SlowDataService = function($timeout){
this.$timeout = $timeout;
};
SlowDataService.$inject = ['$timeout'];
angular.extend(SlowDataService.prototype, {
contacts:[{
name:'Todd Moto',
blog:'http://toddmotto.com/',
twitter:'#toddmotto'
},{
name:'Jeremy Likness',
blog:'http://csharperimage.jeremylikness.com/',
twitter:'#jeremylikness'
},{
name:'John Papa',
blog:'http://www.johnpapa.net/',
twitter:'#John_Papa'
},{
name:'Josh Carroll',
blog:'http://www.technofattie.com/',
twitter:'#jwcarroll'
}],
getContacts:function(){
var _this = this;
return this.$timeout(function(){
return angular.copy(_this.contacts);
}, 1000);
}
});
animateApp.service('slowDataService', SlowDataService);
index.html
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<title>Test Example</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<link rel="stylesheet" href="pace.css">
<script src="http://code.angularjs.org/1.2.13/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular-route.js"></script>
<script src="app.js"></script>
<script src="pace.js"></script>
</head>
<body ng-app="route-change-loader">
<div class="container">
<div class="masthead">
<ul class="nav nav-tabs">
<li>
Default
</li>
<li>
Slow Loading Controller
</li>
</ul>
</div>
<!-- Jumbotron -->
<div class="row">
<route-loading-indicator></route-loading-indicator>
<div ng-if="!isRouteLoading" class="col-lg-12" ng-view=""></div>
</div>
<!-- Site footer -->
<div class="footer">
<p>by <b>Ritesh Karwa</b> </a>
</p>
</div>
</div>
</body>
</html>
default.html
<h1>Click on the tabs to change routes</h1>
route1.html
<h1>{{ctrl.message}}</h1>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Blog</th>
<th>Twitter</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='contact in ctrl.contacts'>
<td>{{contact.name}}</td>
<td>{{contact.blog}}</td>
<td>{{contact.twitter}}</td>
</tr>
</tbody>
</table>

How to change template URL at runtime in AngularJS?

I have in app.js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
// Fetch the data from the API calls
var empDept = GetEmployeeData();
var marFin = GetFinanceData();
var x = 1;
$scope.list = {};
switch(x)
{
case 1: $scope.list = {
EmployeeDepartment: empDept
}; break;
case 2:
$scope.list = {
MarketingFinance: marFin
};break;
}
});
app.directive('myCustomer', function() {
return {
restrict: 'AE',
scope: {
customer: '=myCustomer'
},
replace: true,
templateUrl: 'EmpDept.html'
}
};
});
And my index.html is as under
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<script data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular.js" data-require="angular.js#1.3.x"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<label ng-repeat="(key,val) in list">
<div ng-if="key === 'EmployeeDepartment'">
<table border="1">
<tr>
<td><b>EmployeeNames</b></td>
</tr>
<tbody>
<tr ng-repeat="customer in val" my-customer="customer"></tr>
</tbody>
</table>
<script type="text/ng-template" id="EmpDept.html">
<tr>
<td>{{customer.EmpName}}</td>
</tr>
</script>
</div>
<div ng-if="key === 'MarketingFinance'">
<table border="1">
<tr>
<td><b>Product Name</b></td>
<td><b>Price</b></td>
</tr>
<tbody>
<tr ng-repeat="customer in val" my-customer="customer"></tr>
</tbody>
</table>
<script type="text/ng-template" id="MarkFin.html">
<tr>
<td>{{customer.ProductName}}</td>
<td>{{customer.Price}}</td>
</tr>
</script>
</div>
</label>
</html>
Now the problem is that
Depending on the value of the switch case, the templateURL has to be changed.
e.g
if x=1, templateURL = EmpDept.html
if x=2, templateURL = MarkFin.html
Can you please tell how to do it?
N.B.~ I have seen this but could not plug into the application. Any other easy way?
I have added a plunker that allows you to dynamically change the template URL
http://plnkr.co/edit/yG5qEbFORyyNnCdVDOOY?p=preview
You must add the variable that stores the html link to the directive scope as you can see below:
app.directive('myCustomer', function() {
return {
restrict: 'AE',
scope: {
customer: '=myCustomer',
templateHtml: "="
},
replace: true,
template: '<div ng-include="templateHtml"></div>',
link: function(scope, element, attrs) {
}
};
});

Angularjs modal window with routeProvider

I'm having trouble using routeProvider to display a modal window. I am displaying a table list of ingredients and hoping that by clicking on an ingredient, I can display an "update" modal. The table displays properly and I can even view a single ingredient outside of a modal context but as soon as I try and get the modal working everything falls apart - in fact, the modal doesn't even properly receive its "ingredient" variable. When clicking on a table row the HTML for the modal is displayed like it's a separate page.
app.js:
angular.module('IngredientsApp', [
'IngredientsApp.controllers',
'IngredientsApp.services',
'ngRoute',
'ui.bootstrap'
]).config(['$routeProvider', function($routeProvider) {
$routeProvider.
when("/ingredients", {templateUrl: "partials/ingredients.html", controller: "ingredientsController"}).
when("/ingredient/:id", {templateUrl: "partials/ingredient.html", controller: "ingredientController"}).
otherwise({redirectTo: '/ingredients'});
}]);
services.js:
angular.module('IngredientsApp.services', []).factory('ingredientAPIservice', function($http) {
var ingredientAPI = {};
ingredientAPI.getIngredients = function() {
return $http.get('/ingredient');
}
ingredientAPI.getIngredient = function(id) {
return $http.get('/ingredient/'+id+'/edit');
}
return ingredientAPI;
});
index.html
<!doctype html>
<html lang="en">
<head>
<title>Our Recipes</title>
<script type="text/javascript" src="/js/angular.min.js"></script>
<script type="text/javascript" src="/js/angular-route.min.js"></script>
<script type="text/javascript" src="/js/angular-bootstrap.min.js"></script>
<script type="text/javascript" src="/js/app.js"></script>
<script type="text/javascript" src="/js/services.js"></script>
<script type="text/javascript" src="/js/controllers.js"></script>
<link rel="stylesheet" type="text/css" href="/css/styles.css" />
</head>
<body ng-app="IngredientsApp">
<ng-view></ng-view>
</body>
</html>
ingredients.html
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Existing Ingredients</th>
<th><input type="text" ng-model="descriptionFilter" placeholder="Search..."/></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="i in ingredientsList | filter: searchFilter">
<td>
<a href="/#/ingredient/{{i.Id}}">
{{i.Description}}
</a>
</td>
<td>Created at {{i.CreatedAt}}</td>
</tr>
</tbody>
</table>
ingredient.html
<script type="text/ng-template">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
{{ingredient.Description}}
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Dismiss</button>
</div>
</script>
controllers.js:
angular.module('IngredientsApp.controllers', []).controller('ingredientsController', function($scope, ingredientAPIservice) {
$scope.descriptionFilter = null;
$scope.ingredientsList = [];
$scope.searchFilter = function (ingredient) {
var keyword = new RegExp($scope.descriptionFilter, 'i');
return !$scope.descriptionFilter || keyword.test(ingredient.Description);
};
ingredientAPIservice.getIngredients().success(function (response) {
//Dig into the responde to get the relevant data
$scope.ingredientsList = response;
});
})
var ingredientController = function($scope, $routeParams, $modal, ingredientAPIservice) {
$scope.id = $routeParams.id;
$scope.ingredient = null;
ingredientAPIservice.getIngredient($scope.id).success(function (response) {
$scope.ingredient = response;
$scope.open = function (size) {
var modalInstance = $modal.open({
templateUrl: 'partials/ingredient.html',
controller: 'ingredientModalController',
size: size,
resolve: {
ingredient: function () {
console.log($scope.ingredient);
return $scope.ingredient;
}
}
});
}
});
}
var ingredientModalController = function($scope, $modalInstance, ingredient) {
$scope.ingredient = ingredient;
$scope.ok = function () {
$modalInstance.close($scope.ingredient);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}
I believe your issue is in app.js. Your route change causes the modal template (partials/ingredients.html) to be the only template displayed in ui-view. For the modal to work, you need to have the ingredients template nested within the ingredient template so both templates can be displayed at the same time. There are multiple ways to accomplish this.
If you are willing to give up the route change, just remove
when("/ingredient/:id", {templateUrl: "partials/ingredient.html", controller: "ingredientController"})
If you need the url to change, then I would look at doing it manually through the build in location service. https://docs.angularjs.org/guide/$location
You could just call a function that changes the url on click of an ingredient.

Resources