I'm getting the classic the classic Error: Unknown provider: UserModelProvider <- UserModel with angular JS. My code looks like this:
var ClabborApp = angular.module('clabbor', []);
ClabborApp.factory('UserModel', function() {
var UserModel = {};
var list = [];
UserModel.getItem = function(index) {
return list[index];
}
UserModel.addItem = function(item) {
list.push(item);
}
UserModel.removeItem = function(item) {
list.splice(list.indexOf(item), 1)
}
UserModel.size = function() {
return list.length;
}
return UserModel;
});
function FollowersCtrl($scope, UserModel) {
$scope.followers = [{
text : 'learn angular',
done : true,
'name' : 'James'
}, {
text : 'build an angular app',
done : false,
'name' : 'John'
}];
}
And my html looks like this:
<html lang="en" ng-app>
<meta charset="utf-8">
<body ng-app="clabbor">
<div class="content follow" ng-controller="FollowersCtrl">
<ul class="clearfix">
<!-- Show max 12 followers -->
<li ng-repeat="follower in followers">
{{follower.name}}
</li>
</ul>
</div>
</body>
</html>
I thought I did it by the book but I am getting the error. Does anyone know what could it be?
Remove the ng-app attribute from the html tag. Here's Jsfiddle that's working: http://jsfiddle.net/eA2xx/. You can't have more than one ng-app.
Related
I am using ui-grid to bind data from Role Table which contains Department Id as PrimaryKey. I am calling Web Api to get all the roles in the table and show in ui-grid.
Department Table
Role Table
My real problem is that I want to convert Department Id to Department Name when it binds to grid using cellFilter and that is why I declare objMapping to map Department Id with Department Name. But every time when I run I see that cellFilter custom function i.e. 'mapDepartmentName' is getting called before objMapping is being set and also I am not able to refer objMapping in 'mapDepartmentName'.
My grid looks like this:-
However when I edit I get the result as below which is absolutely correct:-
My code snippet as below:-
var myApp = angular.module('appHome', ['ui.grid', 'ui.grid.edit']);
myApp.controller("ctrlRole", ['$scope', 'MetadataOrgFactory', function ($scope, MetadataOrgFactory) {
var arrDepts = [];
var objMapping = {};
MetadataOrgFactory.getApiCall('getpublisheddepts', function (dataSuccess) {
$scope.department = dataSuccess;
for (var cntElem = 0; cntElem < dataSuccess.length; cntElem++) {
var objDept = { id: dataSuccess[cntElem].DeptId, DeptId: dataSuccess[cntElem].DeptName }
arrDepts.push(objDept);
objMapping[dataSuccess[cntElem].DeptId] = dataSuccess[cntElem].DeptName;
}
$scope.gridRole.columnDefs[1].editDropdownOptionsArray = arrDepts;
}, function (dataError) {
});
$scope.gridRole = {
data: 'roleData',
columnDefs: [
{
field: 'RoleName', displayName: 'Role Name',
},
{
field: 'DeptId', displayName: 'Department Name',
editableCellTemplate: 'ui-grid/dropdownEditor',
cellFilter: 'mapDepartmentName:this',
editDropdownValueLabel: 'DeptId',
},
{
field: 'RoleDesc', displayName: 'About Role',
},
{
field: 'WorkingHrs', displayName: 'Working Hours',
},
{
field: 'RequestNumber', displayName: 'RequestNumber',
cellEditableCondition: true
}
]
}
MetadataOrgFactory.getApiCall('getallroles', function (dataSuccess) {
$scope.roleData = dataSuccess;
}, function (dataError) {
});
}])
.filter('mapDepartmentName', function () {
return function (input, scope) {
if (!input) {
return '';
} else {
return objMapping[input];
}
};
});
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
.gridStyle {
border: 5px solid #d4d4d4;
height: 200px;
}
</style>
<meta charset="utf-8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<link rel="stylesheet" href="https://cdn.rawgit.com/angular-ui/bower-ui-grid/master/ui-grid.min.css" />
<script src="https://cdn.rawgit.com/angular-ui/bower-ui-grid/master/ui-grid.min.js"></script>
<script src="../Scripts/AngularControllers/RoleController.js"></script>
<script src="../Scripts/AngularServices/ApiCallService.js"></script>
</head>
<body ng-app="appHome">
<div ng-controller="ctrlRole">
<div class="gridStyle" ui-grid="gridRole" ui-grid-edit>
</div>
</div>
</body>
</html>
Call $scope.$apply() in getpublisheddepts at the end of factory callback.
as you didnt show ur factory I believe its doing something asynchronously which is not informing the view to reflect changes.
I stuck in the issue for long time.
I did the following change in the code and I am getting the results as well. Please let me know if this is the correct solution for this:-
MetadataOrgFactory.getApiCall('getpublisheddepts', function (dataSuccess) {
$scope.department = dataSuccess;
for (var cntElem = 0; cntElem < dataSuccess.length; cntElem++) {
var objDept = { id: dataSuccess[cntElem].DeptId, DeptId: dataSuccess[cntElem].DeptName }
arrDepts.push(objDept);
objMapping[dataSuccess[cntElem].DeptId] = dataSuccess[cntElem].DeptName;
}
$scope.deptmapping = objDeptMapping; //new code added here
$scope.gridRole.columnDefs[1].editDropdownOptionsArray = arrDepts;
}, function (dataError) {
});
Filter Class
.filter('mapDepartmentName', function () {
return function (input, scope) {
if (!input) {
return '';
} else {
return scope.grid.appScope.deptmapping[input]; //Change in code
}
};
});
I can't seem to get the selected item from an input checkbox.
<ul>
<li ng-repeat='shoe in shoebox'>
<input type='checkbox' ng-model='shoe.selected' id='shoe-{{shoe.name}}'>
<label for='shoe-{{shoe.name}}'>{{shoe.name}}</label>
</li>
<button ng-click='whatIsChecked(shoe.selected)'>Apply</button>
</ul>
Then in my controller:
$scope.whatIsChecked = function(selectedThing) {
console.log(selectedThing);
};
The above returns undefined.
The list items are displayed correctly, but the shoe.name or checked item doesn't seem to be stored by the ng-model.
the variable shoe is only valid in ng-repeat block.
If you want to got what is selected, you should try filter.
UPD:
Since you don't have the selected property, you should keep the selected items somewhere else by firing the ng-click event.
refer below code snippet.
angular.module("app", [])
.controller("myCtrl", function($scope) {
$scope.checkedShoes = [];
$scope.shoebox = [{
name: 'shoe1'
},
{
name: 'shoe2'
},
{
name: 'shoe3'
},
{
name: 'shoe4'
}
];
$scope.save = function(e, shoe) {
if (e.target.checked) {
$scope.checkedShoes.push(shoe);
} else {
var index = $scope.checkedShoes.indexOf(shoe);
if( index > -1) {
$scope.checkedShoes.splice(index, 1);
}
}
};
$scope.whatIsChecked = function() {
//var selected = $scope.shoebox.filter(function(item) {
// return item.selected === true;
//});
console.log($scope.checkedShoes);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="app" , ng-controller="myCtrl">
<ul>
<li ng-repeat='shoe in shoebox'>
<input type='checkbox' ng-click="save($event, shoe)" id='shoe-{{shoe.name}}'>
<label for='shoe-{{shoe.name}}'>{{shoe.name}}</label>
</li>
<button ng-click='whatIsChecked()'>Apply</button>
</ul>
</div>
You can get the checked items using a angular.Foreach it becomes easy when you have multiple items checked.
$scope.checkedItems = [];
angular.forEach($scope.shoebox, function(value, key) {
if (value.selected)
$scope.checkedItems.push(value.name);
});
Demo
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.shoebox = [{
name: 'Reboke',
selected: false
}, {
name: 'woodlands',
selected: false
}, {
name: 'Nike',
selected: false
}, {
name: 'Fila',
selected: false
}];
$scope.checkedItems = function() {
$scope.checkedItems = [];
angular.forEach($scope.shoebox, function(value, key) {
if (value.selected)
$scope.checkedItems.push(value.name);
});
}
});
<html>
<head>
<meta charset="utf-8" />
<title>AngularJS </title>
<link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/1.4.7/angular.js"></script>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<ul>
<li ng-repeat='shoe in shoebox'>
<input type='checkbox' ng-model='shoe.selected' id='shoe-{{shoe.name}}'>
<label for='shoe-{{shoe.name}}'>{{shoe.name}}</label>
</li>
<button ng-click='checkedItems()'>Apply</button>
Checked items are: {{checkedItems}}
</ul>
</body>
</html>
I am trying to to get a JSON array from a server side PHP file. I have the PHP set up to query a MySQL database and return the result as a JSON array. I'm using the ionic framework to develop an app. At the moment I have the app working with a hard coded JSON array, this is what needs to be replaced by the array gained from the PHP.
This is the file where the chats variable should contain the JSON array from the PHP file.
angular.module('starter.services', [])
.factory('Chats', function() {
// Might use a resource here that returns a JSON array
// Some fake testing data
var chats = [{
id: 0,
name: 'Ben Sparrow',
lastText: 'You on your way?',
face: 'img/ben.png'
}, {
id: 1,
name: 'Max Lynx',
lastText: 'Hey, it\'s me',
face: 'img/max.png'
}, {
id: 2,
name: 'Adam Bradleyson',
lastText: 'I should buy a boat',
face: 'img/adam.jpg'
}, {
id: 3,
name: 'Perry Governor',
lastText: 'Look at my mukluks!',
face: 'img/perry.png'
}, {
id: 4,
name: 'Mike Harrington',
lastText: 'This is wicked good ice cream.',
face: '/img/mike.png'
}];
return {
all: function() {
return chats;
},
remove: function(chat) {
chats.splice(chats.indexOf(chat), 1);
},
get: function(chatId) {
for (var i = 0; i < chats.length; i++) {
if (chats[i].id === parseInt(chatId)) {
return chats[i];
}
}
return null;
}
};
});
Here is where the array is accessed from within the application:
<ion-view view-title="Chats">
<ion-content>
<ion-list>
<ion-item class="item-remove-animate item-avatar item-icon-right" ng-repeat="chat in chats" type="item-text-wrap" href="#/tab/chats/{{chat.id}}">
<div class="list card">
<div class="item item-avatar">
<img src="{{chat.face}}">
<h2>{{chat.name}}</h2>
<p>{{chat.lastText}}</p>
</div>
<div class="">
<img ng-src="{{chat.face}}">
</div>
<a class="item item-icon-left assertive" href="#/tab/chats/{{chat.id}}">
<i class="icon ion-cash"></i>
Get Deal!
</a>
</div>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
and below is the PHP file used:
<?php
define('HOST','host');
define('USER','user');
define('PASS','password');
define('DB','db');
$con = mysqli_connect(HOST,USER,PASS,DB);
$sth = mysqli_query($con, "SELECT * FROM chats;");
$rows = array();
while($r = mysqli_fetch_assoc($sth)) {
$rows[] = $r;
}
echo json_encode($rows);
mysqli_close($con);
?>
This is the controller.js:
angular.module('starter.controllers', [])
.controller('DashCtrl', function($scope) {})
.controller('ChatsCtrl', function($scope, Chats) {
// With the new view caching in Ionic, Controllers are only called
// when they are recreated or on app start, instead of every page change.
// To listen for when this page is active (for example, to refresh data),
// listen for the $ionicView.enter event:
//
//$scope.$on('$ionicView.enter', function(e) {
//});
$scope.chats = Chats.all();
$scope.remove = function(chat) {
Chats.remove(chat);
};
})
.controller('ChatDetailCtrl', function($scope, $stateParams, Chats) {
$scope.chat = Chats.get($stateParams.chatId);
})
.controller('AccountCtrl', function($scope) {
$scope.settings = {
enableFriends: true
};
});
I've tried using an async call (which i'm not totally familiar with). I need the array to be ready at the start of the app
Thanks!
This works :
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.factory('chats', function($http){
var chats = [];
var _loading = $http.get('http://swapi.co/api/people').then(function(res){
console.log(res.data.results);
chats = res.data.results;
});
return {
loading: _loading,
all: function(){
return chats;
}
};
});
myApp.controller('ChatsCtrl', function($scope, chats){
$scope.chats = [];
chats.loading.then(function(){
$scope.chats = chats.all();
});
});
</script>
</head>
<body ng-app="myApp">
<div ng-controller="ChatsCtrl">
<ul>
<li ng-repeat="chat in chats">{{chat.name}}</li>
</ul>
</div>
</body>
</html>
Since the Ionic framework is built on Angular, you can use the $http service. You need to request that PHP file from the $http service and then you will be able to read it as JSON. Try something like this for starters:
Make a service that has your API set up already, then call it in your controller file.
angular.module('starter.services', [])
.factory('MYAPI', function() {
return {
getChats: function() {
return $http.get('http://localhost/YOURFILEHERE.php');
}
}
});
Now, in your controller file, assuming you've injected the MYAPI service, you can call
MYAPI.getChats().then(function(response) {
$scope.chats = response.data;
}, function(error) {
console.error(error);
});
You will need to change the $http.get() path to reflect the path of the PHP file on your system.
Say I have an array of keys in a specific order
orderedNames=["mike","bob","sarah];
and I have a JSON that I want to show using ng-repeat but in the order that they appear in the array:
{"people":
{
"bob":{
"hair":"brown",
"eyes":"blue",
"height":"tall"
},
"sarah":{
"hair":"blonde",
"eyes":"blue",
"height":"short"
},
"mike":{
"hair":"red",
"eyes":"blue",
"height":"tall"
}
}
}
How do I write a filer that would cause ng-repeat to spit out the people in the order in which they are specified in the array?
<li ng-repeat="person in people | orderNames"></li>
You can define a custom filter.
Plunker: http://plnkr.co/edit/fiuuGoGZK7tM5oefKQlS
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>Filter Example</title>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.2.x" src="http://code.angularjs.org/1.2.15/angular.js" data-semver="1.2.15"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<li ng-repeat="person in people|orderNames:orderedNames track by $index">{{person.hair}}</li>
</body>
</html>
app.js:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.people={
bob:{
hair:"brown",
eyes:"blue",
height:"tall"
},
sarah:{
hair:"blonde",
eyes:"blue",
height:"short"
},
mike:{
hair:"red",
eyes:"blue",
height:"tall"
}
};
$scope.orderedNames=["mike","bob","sarah"];
});
app.filter("orderNames",function(){
return function(input,sortBy) {
var ordered = [];
for (var key in sortBy) {
ordered.push(input[sortBy[key]]);
}
return ordered;
};
});
You could try something like this
<li ng-repeat="name in orderNames">
{{people[name]}}
</li>
use array as a reference :
http://jsbin.com/jujoj/14/edit
$scope.persons = {
bob:{
name:'bob'
},
mike:{
name: 'mike'
},
sarah: {
name: 'sarah'
}
};
$scope.orderedNames = [$scope.persons.mike, $scope.persons.bob, $scope.persons.sarah];
HTML : <ul ng-repeat="person in orderedNames">
<li>{{ person.name }}</li>
</ul>
to ng-repeat order by another array use
in the controller
$scope.somearray = [1,2,3,4] //or what ever you want to sort by
in the template.
| orderByArray:somearray:true/false
the true/false setting determines if stuff that isn't in the sortby array is outputted after the stuff that is or just dropped.
add the filter
var app = angular.module("app", []).filter("orderByArray", function () {
return function (input, sortBy, includeOrphans) {
//sorts by array and returns items with unsorted items at the end if they are not in the sortby array
if (!angular.isDefined(input)) { return; }
var ordered = [];
var remainder = _.cloneDeep(input);
angular.forEach(sortBy, function (sortitem) {
if (angular.isDefined(input[sortitem])) {
ordered.push(input[sortitem]);
delete (remainder[sortitem]);
}
});
if (includeOrphans) {
angular.forEach(remainder, function (remainingItem, key) {
ordered.push(input[key]);
});
}
return ordered;
};
});
How do I trigger the manipulation of the DOM after a partial view is loaded in AngularJS?
If I were using jQuery, I could do
$(document).ready(function(){
// do stuff here
}
But in Angular, in particular with partial views, how would I do such? As a more concrete example, I have the following basic non-interactive Angular app (html and js on the same page source):
http://cssquirrel.com/testcases/ang-demo/
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Angular Question</title>
</head>
<body data-ng-app="demoApp">
<div data-ng-view=""></div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script>
var app = angular.module('demoApp', []);
var controller = {
demoController: function ($scope, demoFactory) {
$scope.fruits = demoFactory.getFruits();
}
};
var factory = {
demoFactory: function () {
var fruits = ['apples', 'bananas', 'cherries'];
var factory = {
getFruits: function () {
return fruits;
}
};
return factory;
}
}
function appRoute($routeProvider) {
$routeProvider
.when('/step-1',
{
controller: 'demoController',
templateUrl: 'partial.html'
})
.otherwise({ redirectTo: '/step-1' });
};
app.config(appRoute);
app.factory(factory);
app.controller(controller);
</script>
</body>
</html>
Which has the following partial:
http://cssquirrel.com/testcases/ang-demo/partial.html
<ul>
<li data-ng-repeat="fruit in fruits">{{fruit}}</li>
</ul>
So, if in this basic app, I wanted to add a class "active" to the first list item in the list after the partial view has finished loading, how would I go about it?
You have to stop thinking in terms of DOM manipulation. It's not the first LI that's active, rather it's the first fruit that has been selected.
First up, support the concept of a fruit being selected
var fruits = [
{ name: 'apples', active: true },
{ name: 'bananas', active: false },
{ name: 'cherries', active: false }
]
Then, support that attribute with an ng-class in your angular template:
<ul>
<li data-ng-repeat="fruit in fruits" ng-class="{ active: fruit.active }">{{fruit.name}}</li>
</ul>
Now you can manipulate your fruits array and change which one is selected, for example:
$scope.fruits[2].active = true;
AngularJS is model driven. If you want to change DOM, then change data instead.
You can use $first property to activate the first item of the repeater.
<ul>
<li ng-class="{active : $first}" data-ng-repeat="fruit in fruits">{{fruit}}</li>
</ul>
Or if you want to manually activate any item of the repeater by clicking on it, you can change the activate field of the model object.
<ul>
<li ng-class="{true: 'active', false: ''}[fruit.active]" ng-repeat="fruit in fruits" ng-click="activate(fruit)">{{fruit.name}}</li>
</ul>
Use this data structure
var factory = {
demoFactory: function () {
var fruits = [{
name: 'apples',
active: true
}, {
name: 'bananas',
active: false
}, {
name: 'cherries',
active: false
}]
var factory = {
getFruits: function () {
return fruits;
}
};
return factory;
}
}
And add this in the controller.
$scope.activate = function (fruit) {
console.log(fruit)
fruit.active = true;
}
DEMO
You would set an active property on that model and check for adding it to every element.
var controller = {
demoController: function ($scope, demoFactory) {
$scope.fruits = demoFactory.getFruits();
$scope.fruits[0].isActive = true; // kinda hacky
}
};
<ul>
<li data-ng-repeat="fruit in fruits" ng-class="{ active: fruit.isActive }}">{{fruit}}</li>
</ul>
This isn't exactly how I would do it, but with angular it is always best to edit the model so that you maintain 1 single definitive representation of the state of your application.