Implementing a Session Factory - angularjs

I have the following application implementing a Session Service that interacts with the HTML5 window.sessionStorage object. It works well. I'm trying to do the same as the service using a Session Factory but it doesn't work.
My application has the following files:
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<title>Services and Factories</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
</head>
<body ng-controller="sessionController as vm">
<div class="container">
<h1>Services and Factories</h1>
<div class="form-group row">
<div class="col-sm-4">
<label>Name</label>
</div>
<div class="col-sm-8">
<input type="text" class="form-control" ng-model="vm.model.name">
</div>
</div>
<div class="form-group row">
<div class="col-sm-4">
<label>Nickname</label>
</div>
<div class="col-sm-8">
<input type="text" class="form-control" ng-model="vm.model.nickname">
</div>
</div>
<div class="form-group row">
<div class="col-sm-8 col-sm-offset-4">
<input ng-click="vm.setServiceSession()" type="button" class="btn btn-primary" value="Save with Service" />
<input ng-click="vm.getServiceSession()" type="button" class="btn btn-default" value="Retrieve from Service" />
<input ng-click="vm.clearServiceSession()" type="button" class="btn btn-default" value="Clear from Service" />
</div>
</div>
<pre>{{vm.model | json}}</pre>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<script src="app/app.js"></script>
<script src="app/sessionController.js"></script>
<script src="app/sessionService.js"></script>
</body>
</html>
app/app.js
angular.module('app', []);
app/sessionController.js
angular.module('app').controller('sessionController', ['sessionService', sessionController]);
function sessionController(sessionService) {
var vm = this;
vm.getServiceSession = function() {
vm.model = {
name: sessionService.get('name'),
nickname: sessionService.get('nickname'),
status: 'Retrieved by service on ' + new Date()
};
};
vm.setServiceSession = function() {
sessionService.save('name', vm.model.name);
sessionService.save('nickname', vm.model.nickname);
vm.getServiceSession();
};
vm.clearServiceSession = function() {
sessionService.clear();
vm.getServiceSession();
};
}
app/sessionService.js
angular.module('app').service('sessionService', ['$window', sessionService]);
function sessionService($window) {
this.save = save;
this.get = get;
this.clear = clear;
function save(key, value) {
$window.sessionStorage.setItem(key, value);
}
function get(key, value) {
return $window.sessionStorage.getItem(key);
}
function clear() {
$window.sessionStorage.clear();
}
}
The Session Service works well. Then I try to add a Session Factory to do the same as the Session Service, but everything stops working. I add the following file:
app/sessionFactory.js
angular.module('app').factory('sessionFactory', ['$window', sessionFactory]);
function sessionFactory($window) {
return {
save: save,
get: get,
clear: clear
};
function save(key, value) {
$window.sessionStorage.setItem(key, value);
}
function get(key, value) {
return $window.sessionStorage.getItem(key);
}
function clear() {
$window.sessionStorage.clear();
}
}
And I modify:
index.html (adding 3 new buttons to for the Factory and the sessionFactory script)
<div class="form-group row">
<div class="col-sm-8 col-sm-offset-4">
<input type="button" class="btn btn-primary" value="Save with Factory" ng-click="vm.setFactorySession()" />
<input type="button" class="btn btn-default" value="Retrieve from Factory" ng-click="vm.getFactorySession()" />
<input type="button" class="btn btn-default" value="Clear from Factory" ng-click="vm.clearFactorySession()" />
</div>
</div>
...
<script src="app/sessionFactory.js"></script>
sessionController.js (adding the sessionFactory)
angular.module('app').controller('sessionController', ['sessionService', 'sessionFactory', sessionController]);
function sessionController(sessionService, sessionFactory) {
...
var mySessionFactory = new sessionFactory();
vm.getFactorySession = getFactorySession;
vm.setFactorySession = setFactorySession;
vm.clearFactorySession = clearFactorySession;
function getFactorySession() {
vm.model = {
name: mySessionFactory.get('name'),
nickname: mySessionFactory.get('nickname'),
status: 'Retrieved by Factory on ' + new Date()
};
}
function setFactorySession() {
mySessionFactory.save('name', vm.model.name);
mySessionFactory.save('nickname', vm.model.nickname);
getFactorySession();
}
function clearFactorySession() {
mySessionFactory.clear();
getFactorySession();
}
}

As factories and services are singletone you don't need to use new. Just remove that and do the same.
remove:
var mySessionFactory = new sessionFactory();
All the best.

You don't need to use new sessionFactory() when using a factory.
Instead, use sessionFactory.get('name') and it will work.
This is the main difference between service and factory.
Check this blog post for more insights.

Related

How to store values from a form to local storage in AngularJS?

I have some code for adding the values from a form to the local storage,
but when I tried the code, it is not running. I would like to store the form data in local storage by clicking the button. I am adding my sample code below:
App.controller('KeyController', function($scope,$localStorage) {
/*$scope.info = 'Welcome to Test';*/
/*console.log(" Key controller is working ");*/
$scope.api_url;
$scope.api_token;
$scope.submit=function(){
localStorage.setItem('api_url','--------');
localStorage.setItem('api_token','--------');
console.log(api_url);
console.log(api_token)
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="container">
<form role = "form" id="uriForm" name="authfrom">
<div class = "form-group">
<label for = "url">Enter the url to authenticate:</label>
<input type = "url" class = "form-control" placeholder = "Enter the URL" ng-model="api_url" required="required">
</div>
<div class = "form-group">
<label for = "Key">Enter the key here:</label>
<textarea class = "form-control" rows="5" placeholder = "Enter the Key" ng-model="api_token" required="required"></textarea>
</div>
<button class = "btn btn-default" ng-click="submit()">Explore!!</button>
<p class="warning">{{failed}}</p>
</form>
</div>
You haven't add your app.js file in html.
You didn't add your ng-app and ng-controller in html.
You were adding $localStorage in function which is not necessary.
You were using wrong syntax for localStorage.setItem()
Now I've edited your code and made this.
Here is index.html page
<!DOCTYPE html>
<html ng-app="app">
<head>
<title>App</title>
<script src="angular/angular.min.js"></script>
<script type="text/javascript" src="app.js"></script>
</head>
<body ng-controller="KeyController">
<div class="container">
<form>
<div class = "form-group">
<label for = "url">Enter the url to authenticate:</label>
<input type = "text" class = "form-control" placeholder = "Enter the URL" ng-model="api_url" required="required">
</div>
<div class = "form-group">
<label for = "Key">Enter the key here:</label>
<textarea class = "form-control" rows="5" placeholder = "Enter the Key" ng-model="api_token" required="required"></textarea>
</div>
<button class = "btn btn-default" ng-click="submit()">Explore!!</button>
<p class="warning">{{failed}}</p>
</form>
</div>
</body>
</html>
Here is your app.js file:
angular.module('app', [])
.controller('KeyController', function($scope) {
$scope.api_url;
$scope.api_token;
$scope.submit=function(){
localStorage.setItem('api_url', JSON.stringify($scope.api_url));
localStorage.setItem('api_token', JSON.stringify($scope.api_token));
console.log($scope.api_url);
console.log($scope.api_token)
}
});
You can copy paste this and check your self. First replace the reference of angular.min.js file.
Please go through the below code which has been corrected to bootstrap the angular module and set controller using ng-app and ng-controller.
Code snippets posted on stackoverflow cannot access localstorage for the reason mentioned here. So you'll need to run this code on your local development environment.
angular
.module('MyApp', []);
angular
.module('MyApp')
.controller('KeyController', [
'$scope',
function($scope) {
/*$scope.info = 'Welcome to Test';*/
/*console.log(" Key controller is working ");*/
$scope.api_url;
$scope.api_token;
$scope.savedApiUrl = '';
$scope.savedApiToken = '';
$scope.submit = function() {
localStorage.setItem('api_url', $scope.api_url);
localStorage.setItem('api_token', $scope.api_token);
var savedApiUrl = localStorage.getItem('api_url');
var savedApiToken = localStorage.getItem('api_token');
$scope.savedApiUrl = savedApiUrl;
$scope.savedApiToken = savedApiToken;
console.log($scope.savedApiUrl);
console.log($scope.savedApiToken)
}
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="container" ng-app="MyApp" ng-controller="KeyController">
<form role="form" id="uriForm" name="authfrom">
<div class="form-group">
<label for="url">Enter the url to authenticate:</label>
<input type="url" class="form-control" placeholder="Enter the URL" ng-model="api_url" required="required">
</div>
<div class="form-group">
<label for="Key">Enter the key here:</label>
<textarea class="form-control" rows="5" placeholder="Enter the Key" ng-model="api_token" required="required"></textarea>
</div>
<button class="btn btn-default" ng-click="submit()">Explore!!</button>
<p class="warning">{{failed}}</p>
</form>
<p>Saved values from local storage</p>
<p>API URL: {{savedApiUrl}}</p>
<p>API Token: {{savedApiToken}}</p>
</div>

MEAN stack editing a post

So I am working on my very first MEAN stack app and I am using using type script.
I have my post working just fine, but my edit post is not working. Since this is my first app I am not quite sure why. The error says that my parameters for my post are undefined. I hope one of you lovely people can help me out. I've avoided asking for help for a long time because I am sure its a stupid error.
controllers.ts
http://pastebin.com/bhXT5bLz
app.ts
state('jobPost', {
url: '/jobPost',
templateUrl: "/templates/jobPost.html",
controller: MyApp.Controllers.jobPostController,
controllerAs: 'jobPost'
})
.state('editjobPost', {
url: '/editjobPost',
templateUrl: "/templates/jobPost.html",
controller: MyApp.Controllers.jobPostController,
controllerAs: 'jobPost'
})
route.ts:
router.get('/jobPostData', function (req, res) {
console.log('getting jobPost data');
JobPost.find({}, function(err, jobposts) {
res.json(jobposts);
});
});
router.put('/jobPost', function (req, res, next) {
console.log('editing jobPost');
let jobPost = new JobPost({
jobTitle: req.body.jobTitle,
jobLocation: req.body.jobLocation,
jobDescription: req.body.jobDescription,
created_at: req.body.created_at
});
console.log(jobPost);
jobPost.save(function(err, jobPost) {
if (err) return next(err);
console.log('edited post');
res.send(jobPost);
});
});
jobPost.html:
<link rel="stylesheet" href="/css/jobPost.css" media="screen" title="no title" charset="utf-8">
<br><br><br><br><br><br><br>
<div class="container-fluid">
<div class="container">
<div class="row">
<div ng-show="jobPost.newForm" class="col-md-12" id="background">
<h1 class="headers">Post a Job</h1>
<form ng-submit="jobPost.newJobPost()" class="new_job_form" name="new_job_form">
<input ng-model="jobPost.jobPost.title" id="jobTitle" type="text" name="jobTitle" placeholder="job title"> <br><br>
<input ng-model="jobPost.jobPost.location" id="jobLocation" type="text" name="jobLocation" placeholder="job location"> <br><br>
<textarea ng-model="jobPost.jobPost.description" rows="8" cols="50"class="input-block-level" id="jobDescription" name="jobDescription" placeholder="Enter Description" ></textarea><br>
<input class="submit-btn" type="submit" name="submit" value="Submit">
</form>
<!-- <h2>{{jobPost.message}}</h2> -->
</div>
<div ng-show="jobPost.editForm" class="col-md-12" id="background">
<h1 class="headers">Edit a Job</h1>
<form ng-submit="jobPost.editJobPost()" class="edit_job_form" name="edit_job_form">
<input ng-model="jobPost.jobPost.title" type="text" name="jobTitle" value="{{editJobPost.editTitle}}"> <br><br>
<input ng-model="jobPost.jobPost.location" type="text" name="jobLocation" value="{{editJobPost.editLocation}}"> <br><br>
<textarea ng-model="jobPost.jobPost.description" rows="8" cols="50"class="input-block-level" name="jobDescription" value="{{editJobPost.editDescription}}" ></textarea><br>
<input class="submit-btn" type="submit" name="submit" value="Submit">
</form>
</div>
</div
</div>
</div>
</div>
<br><br>
<div class="container-fluid">
<div class="container">
<h1 class="headers">Your Jobs</h1>
<div class="row" ng-repeat="job in jobPost.jobPosts.slice(((jobPost.currentPage-1)*jobPost.itemsPerPage),((jobPost.currentPage)*jobPost.itemsPerPage)) | orderBy : 'created_at' ">
<h1></h1>
<div class="col-md-12 jobPosting panel-title">
<h2>{{job.jobTitle}}<a class="pull-right" ui-sref="editjobPost"><span ng-click="jobPost.editJobPost()" class="glyphicon glyphicon-cog"></a></h2>
<h3>{{job.jobLocation}}</h3>
<h3>{{job.jobDescription}}</h3>
</div>
</div>
<!-- <pagination total-items="jobPost.totalItems" ng-model="jobPost.currentPage" ng-change="jobPost.pageChanged()" class="pagination-sm" items-per-page="jobPost.itemsPerPage"></pagination> -->
<ul uib-pagination total-items="jobPost.totalItems" items-per-page="jobPost.itemsPerPage" ng-model="jobPost.currentPage" ng-change="jobPost.pageChanged()"></ul>
<!-- <ul uib-pagination total-items="totalItems" ng-model="JobPost" ng-change="pageChanged()"></ul> -->
<!-- <h4>Default</h4>
<h5>totalItems: {{jobPost.totalItems}}</h5>
<ul uib-pagination total-items="jobPost.totalItems" ng-model="jobPost.currentPage" ng-change="jobPost.pageChanged()"></ul> -->
<!-- <ul uib-pagination boundary-links="true" total-items="jobPost.totalItems" ng-model="jobPost.currentPage" class="pagination-sm" previous-text="‹" next-text="›" first-text="«" last-text="»"></ul>
<ul uib-pagination direction-links="false" boundary-links="true" total-items="jobPost.totalItems" ng-model="jobPost.currentPage"></ul>
<ul uib-pagination direction-links="false" total-items="jobPost.totalItems" ng-model="jobPost.currentPage" num-pages="smallnumPages"></ul>
<pre>The selected page no: {{jobPost.currentPage}}</pre>
<button type="button" class="btn btn-info" ng-click="jobPost.setPage(3)">Set current page to: 3</button> -->
<hr />
</div>
</div>
<script src="/js/jobForm.js" charset="utf-8"></script>
jobForm.ts:
$(document).ready(function() {
$('.new_job_form').on('submit', function(e){
e.preventDefault();
var jobTitle = $('#jobTitle').val();
var jobLocation = $('#jobLocation').val();
var jobDescription = $('#jobDescription').val();
$('#jobTitle').val('');
$('#jobLocation').val('');
$('#jobDescription').val('');
var data = {
jobTitle: jobTitle,
jobLocation: jobLocation,
jobDescription: jobDescription,
};
console.log(data);
$.ajax({
url: '/jobPost',
dataType: "json",
method: "POST",
data: data,
success: function(data, textStatus, jqXHR){
console.log("Successfully saved to database",data);
// var resultString = "<h4>"+data.jobTitle+"</h4><h4>"+data.jobLocation+"</h4><h4>"+data.jobDescription+"</h4>";
// $('.postResult').html(resultString);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
alert("Status: " + textStatus); alert("Error: " + errorThrown);
}
});
});
angular.module('MyApp').controller('jobPostController', function ($scope, $log) {
$scope.totalItems = 64;
$scope.currentPage = 1;
$scope.setPage = function (pageNo) {
$scope.currentPage = pageNo;
};
$scope.pageChanged = function() {
$log.log('Page changed to: ' + $scope.currentPage);
};
$scope.maxSize = 5;
$scope.bigTotalItems = 175;
$scope.bigCurrentPage = 1;
});
});
****EDIT to reflect answering stack overflow checklist
I have tried messing with the ui-sref and ng-click for the editJobPost section in the JobPost.html thinking maybe it was a routing error.
I then changed the editJobPost method in controller.js from the JobPost variable to JobPosts variable. Now that it runs and compiles (it didn't before) it throws this in the console:
HITTING EDIT
controllers.js:241 undefined
controllers.js:242 undefined
controllers.js:245 undefined
controllers.js:249 Title: undefined
controllers.js:250 Location: undefined
controllers.js:251 Description: undefined
angular.js:11881 PUT http://127.0.0.1:3000/jobPost/%7B%7Bjob._id%7D%7D 404 (Not Found)
I know that it means my declared variables are undefined, I just don't know where to start. what is wrong and why.

validate dynamic form before submitting angular

I'm dynamically creating forms with ng-repeat and they have some validation attributes (simplified version):
<div class="row" ng-repeat="defect in model.defects">
<form name="form_{{defect.id}}" novalidate>
<input ng-model="defect.name" required/>
<input type="submit" ng-click="saveDefect(defect)"/>
</form>
</div>
Basically what I want to do is this:
$scope.saveDefect = function (defect) {
if ($scope.<how to get the form name here>.$invalid) {
return;
}
}
Since the form name has been created dynamically with an id how do I access it? Other ways of doing the same are also welcome ofcourse :)
You can use the bracket notation to access it :
$scope["form_"+defect.id]
What I advise you to do is :
var app = angular.module("App", []);
app.controller("Ctrl", function($scope) {
$scope.forms = {};
$scope.list = [{id: 1}, {id: 2}];
$scope.save = function(item) {
if ($scope.forms["form_" + item.id].$invalid) {
alert("error on form_" + item.id);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="App" ng-controller="Ctrl">
<div class="row" ng-repeat="item in list">
<form name="forms.form_{{item.id}}" novalidate>
<input ng-model="item.name" required/>
<input type="submit" ng-click="save(item)" />
</form>
</div>
</body>

AngularJS app go back to inital state automatically

Following app shows three todo items at first and
after adding an new data, it shows updated lists for a moment and go back to the original state.
Could you tell me why does it go back to the initial state automatically?
link for Pluker
http://plnkr.co/edit/h6THusBe7AWFle5ixXzX?p=preview
==================================
<!DOCTYPE html>
<html ng-app="initExample">
<head>
<link data-require="bootstrap-css#*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<script src="https://code.angularjs.org/1.4.0-beta.5/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body class="well" ng-controller="ExampleController">
<h1> AngularJS Todo List</h1>
<p> Total <strong> {{todolist.length}} </strong> / Remain <strong> {{countRemain()}} </strong> </p>
<ul>
<li ng-repeat="todo in todolist" class="checkbox"> <input ng-model="todo.done" type="checkbox"> {{todo.title}}</li>
</ul>
<form name="newItemForm" class="form-inline" action="">
<div class="form-group">
<label class="sr-only" for="newItemText" placeholder="Type new ToDo"></label>
<input type="text" class="form-control" ng-model="newTodo" name="newItemText" placeholder="Type new Todo">
</div>
<button type="submit" ng-click="addNewTodo(newTodo)" class="btn btn-default"> Add </button>
</form>
</body>
</html>
============================
// Code goes here
var mymodule=angular.module('initExample', []);
mymodule.controller('ExampleController',
['$scope', function($scope) {
$scope.todolist = [
{done: true, title:'AngularJS study'},
{done: false, title:'music listening'},
{done: false, title:'run'}
];
$scope.countRemain = function() {
var count = 0;
var list = $scope.todolist;
angular.forEach(list, function(val, key) {
if(!list[key].done) count++;
});
return count;
};
$scope.addNewTodo = function(newTodo) {
todolist.push({done: false, title: newTodo});
};
}
]
);
Remove the action attribute from the form or add "preventDefault" from the button click.
Fixed the plunkr:
<form name="newItemForm" class="form-inline">
http://plnkr.co/edit/KFpbbdlDPbnIPAW43EaG?p=preview
P.S. also fixed the addNewTodo Function:
$scope.addNewTodo = function(newTodo) {
$scope.todolist.push({done: false, title: newTodo});
};
You need to remove action attribute from form definition, otherwise browser will try to submit it, reloading the page:
<form name="newItemForm" class="form-inline">
<!-- ... -->
</form>
Demo: http://plnkr.co/edit/MwTmGqzdELzUbrY82kKg?p=preview

AngularJS and Angular-UI Bootstrap tabs scope

I am using AngularJS and Angular-UI Bootstrap tabs. This is my controller:
app.controller("SettingsCtrl", ['$scope','SettingsFactory','$stateParams', function($scope,SettingsFactory,$stateParams){
$scope.navType = 'pills';
$scope.saveLanguage = function()
{
console.log($scope.test.vari); // loged undefined
}
}]);
My view
<div class="row clearfix">
<tabset>
<tab heading="Jezik">
<form role="form" name="test">
<div class="form-group">
<label for="lang">Izaberite jezik</label>
<select class="form-control" ng-model="vari">
<option>Hrvatski</option>
<option>Srpski</option>
<option>Bosanski</option>
<option>Engleski jezik</option>
<option>Njemački jezik</option>
</select>
</div>
<button type="submit" class="btn btn-default" ng-click="saveLanguage()">Save</button>
</form>
</tab>
</div>
Can someone help me to see why is loging undefined when I am using Angular-UI Bootstrap Tabs. Is it creating own scope. How tu access model value ?
This code solved my problem (removed name atribute from form, added ng-model="test.vari", and added $scope.test= {} in my controller) :
<tabset>
<tab heading="Jezik">
<form role="form">
<div class="form-group">
<label for="lang">Izaberite jezik</label>
<select class="form-control" ng-model="test.vari">
<option>Hrvatski</option>
<option>Srpski</option>
<option>Bosanski</option>
<option>Engleski jezik</option>
<option>Njemački jezik</option>
</select>
</div>
<button type="submit" class="btn btn-default" ng-click="saveLanguage()">Spremi Jezik</button>
</form>
</tab>
</div>
app.controller("SettingsCtrl", ['$scope','SettingsFactory','$stateParams', function($scope,SettingsFactory,$stateParams){
$scope.navType = 'pills';
$scope.test= {};
$scope.saveLanguage = function()
{
console.log($scope.test.vari);
// SettingsFactory.update({ id:$stateParams.user_id }, $scope.language);
}
}]);
The tab creates child scopes so we need to bind it to an expression that evaluates to a model in the parent scope.
For this, the model must use a . like this:
ng-model='object.variable'
And we must declare the object in controller's top:
$scope.object = {};
Example:
angular.module('test', ['ui.bootstrap']);
var DemoCtrl = function ($scope) {
$scope.obj = {text: ''};
$scope.show = function() {
alert('You typed: ' + $scope.obj.text)
}
};
<!doctype html>
<html ng-app="test">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.14.0.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="DemoCtrl">
Value outside the tabs: {{obj.text}}
<uib-tabset>
<uib-tab heading="Tab 1">
<input ng-model="obj.text">
<button ng-click="show()">Show</button>
</tab>
</tabset>
</div>
</body>
</html>

Resources