Angular changing object in scope doesn't change view - javascript

Screencast: http://screencast-o-matic.com/watch/cDjX00isoo
All Javascript: http://fontget.com/js/all.js (at the bottom)
Demo of the issue: http://www.fontget.com
So I have this issue that I have been dealing with for a bit and can't seem to be able to figure it out. I am trying to give users the option of sorting the results from the database by clicking on a radio button with the specific filter.
When I click on the radio button I can see in the console that the correct url is grabbed using AJAX but the list is not getting updated in the view.
The page works when it is loaded for the first time (no sort filters).
The controller:
FontGet.controller('mainController', ['$scope', 'FontService', '$location', '$rootScope', '$routeParams', function($scope, FontService, $location, $rootScope, $routeParams) {
$rootScope.hideFatMenu = false;
$scope.navCollapsed = true;
$scope.isSettingsCollapsed = true;
$rootScope.header = "Welcome to FontGet.com!";
$scope.sortBy = 'new';
$scope.fonts = {
total: 0,
per_page: 10,
current_page: ((typeof($routeParams.page) !== 'undefined') ? $routeParams.page : 1),
loading: true
};
$scope.setPage = function() {
FontService.call('fonts', { page: $scope.fonts.current_page, sort: $scope.sortBy }).then( function(data) {
$scope.fonts = data.data;
$scope.fonts.loading = false;
document.body.scrollTop = document.documentElement.scrollTop = 0;
});
};
$scope.$watch("sortBy", function(value) {
$scope.setPage();
});
$scope.$watch("searchQuery", function(value) {
if (value) {
$location.path("/search/" + value);
}
});
$scope.categories = FontService.categories();
$scope.setPage();
}]);
The View:
<div class="fontdd" ng-repeat="font in fonts.data" >
<!-- Stuff goes here. This is populated correctly when page initially loads -->
</div>
The sort buttons:
<ul class="radiobtns">
<li>
<div class="radio-btn">
<input type="radio" value="value-1" id="rc1" name="rc1" ng-model="sorts" ng-change="sortBy = 'popular'">
<label for="rc1" >Popularity</label>
</div>
</li>
<li>
<div class="radio-btn">
<input type="radio" value="value-2" id="rc2" name="rc1" ng-model="sorts" ng-change="sortBy = 'trending'">
<label for="rc2">Trending</label>
</div>
</li>
<li>
<div class="radio-btn">
<input type="radio" value="value-4" id="rc4" name="rc1" checked="checked" ng-model="sorts" ng-change="sortBy = 'new'">
<label for="rc4">Newest</label>
</div>
</li>
<li>
<div class="radio-btn">
<input type="radio" value="value-3" id="rc3" name="rc1" ng-model="sorts" ng-change="sortBy = 'alphabetical'">
<label for="rc3">Alphabetical</label>
</div>
</li>
</ul>
You will notice that the ng-model for the radio buttons is not set to sortBy. The reason for this is that if I set it to sortBy the AJAX call is made 4 times (no clue why thi is happening).

You're using a $scope.$watch function to watch for changes in the sortBy scope variable. You should try removing the watch and change your sort buttons' ng-change event to this:
<div class="radio-btn">
<input type="radio" value="value-1" id="rc1" name="rc1" ng-model="sorts" ng-change="Sort('popular')">
<label for="rc1" >Popularity</label>
</div>
In your controller, create a Sort() function:
$scope.Sort = function(sortBy) {
$scope.sortBy = sortBy;
$scope.setPage();
}
You don't really need to use $watch when you can just call a function and pass in the appropriate information.

Related

Getting a 405 (Method Not Allowed) in AngularJS

So, I am creating a web app, where one page I have a user list and on the second page, I have the users details page. On the second page, I have a confirm button where I want to remove that user when the "Confirm" button is clicked with a 200 Status code. However, I am getting a DELETE : 405 (Method Not Allowed). So, here is my code down below. Please tell me or help me fix this problem. Thank you in advance.
Here is my code.
<div ng-controller="MyCtrl">
<div ng-repeat="person in userInfo.lawyers | filter : {id: lawyerId}">
<a class="back" href="#/lawyer">Back</a>
<button type="button" class="edit" ng-show="inactive" ng-click="inactive = !inactive">
Edit
</button>
<button type="submit" class="submit" ng-show="!inactive" ng-click="inactive = !inactive">Save</button>
<button class="btn btn-primary" ng-click="doDelete(id)">Confirm</button>
<div class="people-view">
<h2 class="name">{{person.firstName}}</h2>
<h2 class="name">{{person.lastName}}</h2>
<span class="title">{{person.email}}</span>
<span class="date">{{person.website}} </span>
</div>
<div class="list-view">
<form>
<fieldset ng-disabled="inactive">
<legend>Basic Info</legend>
<b>First Name:</b>
<input type="text" ng-model="person.firstName">
<br>
<b>Last Name:</b>
<input type="text" ng-model="person.lastName">
<br>
<b>Email:</b>
<input type="email" ng-model="person.email">
</fieldset>
</form>
</div>
</div>
</div>
Services
app.factory('people', function ($http) {
var service = {};
service.getUserInfo = function () {
return $http.get('https://api-dev.mysite.io/admin/v1/unconfirmed_lawyers');
};
service.confirmUser = function (lawyerId) {
return $http.put('https://api-dev.mysite.io/admin/v1/lawyers/{lawyerId}/confirm');
};
return service;
});
LawyerController
app.controller('LawyerController', ['$scope', 'people', '$routeParams',
function ($scope, people, $routeParams) {
$scope.lawyerId = $routeParams.id;
people.getUserInfo().then(function (response) {
$scope.userInfo = response.data;
});
}]);
HomeController
var isConfirmed = false;
app.controller('HomeController', function($scope, people, $http) {
if (!isConfirmed) {
people.getUserInfo().then(function (response) {
$scope.userInfo = response.data;
}, function (error) {
console.log(error)
});
}
});
App.js
$scope.doDelete = function(lawyer) {
var index = $scope.userInfo.lawyers.indexOf(lawyer);
$scope.userInfo.lawyers.splice(index, 1);
location.href = '#/lawyer';
};
If you changed your HTML, so you passed the person instead.
<button class="btn btn-primary" ng-click="doDelete(person)">Confirm</button>
You can use this to find the index within the lawyers, then remove it.
$scope.doDelete = function(lawyer) {
var index = $scope.userInfo.lawyers.indexOf(lawyer);
$scope.userInfo.lawyers.splice(index, 1)
};
The issue is your are using $http.delete which performs an HTTP Delete request. This doesn't sound like something you intended.

Update page after form submit - using Angular

I am using the MEAN framework - I have a basic form (as per below) that when data is entered it is sent to a rest API which then has a function that uses Mongoose to save data. That is all good... however i'm stuck on something more basic!
After a user has submitted this form it lands on a blank page with the api/img/add, how do i go back to my original page? I tried adding ng-submit="fetchImages()" within the form tag and then implementing a function in a script (also shown below) but for some reason this was not working, am i missing the point and doing something really wrong?
Thanks in advance
<form action="api/img/add" method="post" enctype="multipart/form-data">
<div>
<label for="image">Select an image</label>
<input type="file" name="image" id="image">
</div>
<div>
<label for="title">Title</label>
<input type="text" name="title" id="title">
</div>
<input type="submit">
</form>
< script >
angular.module('app', []).controller('main', ['$scope', '$http',
function($scope, $http) {
$scope.images = [];
$scope.fetchImages = function() {
$scope.images = [];
$http.get('api/img').then(function(res) {
$scope.images = JSON.parse(res.data);
}, function(res) {
console.log(res.statusText);
});
}
$scope.fetchImages();
}
]); < /script>
If you literally want to go back to the last page, you could use:
$window.history.back();
In your example, I would create the function in the controller as outlined below, and change
<input type="submit">
to
<input type="submit" ng-click="goHome()">
I created an über-simple plunk here with a button that will take you back:
https://plnkr.co/edit/wzMlPF9kOmrGg01mOnBB?p=preview
JS
app.controller('ctrl',function($scope,$window){
$scope.goHome = function() {
$window.history.back();
}
});
HTML
<button ng-click="goHome()">Go Home</button>
Try this:
In html
<form ng-submit="submitData()">
<div>
<label for="image">Select an image</label>
<input type="file" ng-model="formdata.image" id="image">
</div>
<div>
<label for="title">Title</label>
<input type="text" ng-model="formdata.title" id="title">
</div>
<input type="submit">
</form>
In your controller:
angular.module('app', []).controller('main', ['$scope', '$http',
function($scope, $http) {
$scope.formdata = {};
$scope.images = [];
$scope.fetchImages = function() {
$scope.images = [];
$http.get('api/img').then(function(res) {
$scope.images = JSON.parse(res.data);
}, function(res) {
console.log(res.statusText);
});
}
$scope.fetchImages();
//this function will post data to your api without refreshing the page
$scope.submitData = function(){
$http.post('api-comes-here', $scope.formdata).then(function(res) {
//handle success
}, function(error) {
//handle error
});
}
}

Controller and input form html use var Javascript

I use the angularjs framework, I created an form.html and a controller.js with a variable that retrieves the SSID of a box.
How to automatically assign the value of the variable in the form.
This is an input field.
When launching the application, the form should display the SSID automatically without the user needing to do so.
Thank you kindly help me.
'use strict';
angular.module('djoro.controllers')
.controller('WifiSmartConfigCtrl', function ($scope, $window, $ionicPlatform) {
$scope.getSSID = function () {
var onSuccess = function (SSID) {
document.write(SSID);
};
var onFail = function () {
};
$ionicPlatform.ready(function () {
$window.cordova.plugins.Smartconfig.getSSID(onSuccess, onFail);
});
};
});
<ion-pane>
<ion-content ng-controller="WifiSmartConfigCtrl">
<form novalidate class="simple-form">
<fieldset>
<legend>WI-FI</legend>
<div class="list input-fields">
<label class="item item-input">
<span class="input-label">SSID :</span>
<input type="text" name="test" value="getSSID()" required show-hide-input>
</label>
<label class="item item-input" show-hide-container>
<span class="input-label">Password :</span>
<input type="text" name="password" required show-hide-input>
</label>
</div>
</fieldset>
</form>
</ion-content>
</ion-pane>
use the ng-model directive, it's exactly it's purpose :
'use strict';
angular.module('djoro.controllers')
.controller('WifiSmartConfigCtrl', function($scope, $window, $ionicPlatform) {
$scope.SSID = {};
$scope.getSSID = function() {
var onSuccess = function(SSID) {
$scope.SSID = SSID;
};
var onFail = function() {};
$ionicPlatform.ready(function() {
$window.cordova.plugins.Smartconfig.getSSID(onSuccess, onFail);
});
};
});
and in your view :
<input type="text" name="test" ng-model="SSID" required show-hide-input>
You need to add an ng-model to the input field like so:
<label class="item item-input">
<span class="input-label">SSID :</span>
<input type="text" name="test" ng-model="SSID" required show-hide-input>
</label>
then in your controller assign the value of SSID on the $scope:
$scope.SSID = [some_value]
see this plnkr
As you can see I have assigned the value of SSID manually, you can add it dynamically by assigning it in the callback of your function like so:
$scope.SSID = {}
var onSuccess = function (SSID) {
document.write(SSID);
$scope.SSID = SSID
};

Disable required attribute on one radio button

I have 3 radio buttons in a bootstrap modal and I want only 2 of them to be required in order to submit the form. I created a requiredCheck() function that's using a jQuery implementation so I'd rather not use this. What is the best way to disable the required attribute for one radio button, when using AngularJS?
HTML
<form name="jawn">
<div class="modal-header">
<h3 class="modal-title">Jawn</h3>
</div><!-- /modal-header -->
<div class="modal-body">
<ul>
<li ng-repeat="item in items">
<label for="optionsRadios">
<input type="radio" ng-model="$parent.data.status" name="optionsRadios" ng-value="item.id" required/ ng-click="requiredCheck()"> {{item.name}}
</label>
</li>
</ul>
<h4>Comment</h4>
<textarea ng-class="{error: thing.comment.$dirty && thing.comment.$invalid}" type="text" rows="3" cols="64" ng-model="data.comment" ng-minlength="4" ng-required></textarea>
<span class="error" ng-show="thing.comment.$error.required">required</span>
</div><!-- /modal-body-->
<div class="modal-footer">
<button type="submit" class="btn btn-warning" ng-click="ok()" ng-disabled="thing.$invalid">Part Jawn</button>
<button type="button" ng-click="cancel()" class="btn btn-default">Cancel</button>
</div>
</form>
JavaScript
angular.module('app')
.controller('ModalController', function($scope, $modalInstance, $timeout) {
'use strict';
$scope.item = 0;
$scope.items = [
"Zero": 0,
"Uno": 1,
"Dos": 2
];
$scope.requiredCheck = function () {
var $btnWarning = $('.btn-warning');
var $textarea = $('textarea');
$timeout(function() {
if($scope.data.status === item.Dos) {
$btnWarning.removeAttr('disabled');
$textarea.removeAttr('required');
} else if ($scope.data.status === 3) {
$btnWarning.prop('disabled',true);
$textarea.prop('required', true);
} else if ($scope.data.status === 3) {
$btnWarning.prop('disabled',true);
$textarea.prop('required', true);
}
},100);
};
$scope.ok = function () {
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
$modalInstance.close();
};
});
You should use angualrjs approach. As you have already specified ngRequired set true/false from controller.
From DOCs
ngRequired: Sets required attribute if set to true
HTML
<textarea ng-model="data.comment" ng-required="textRequired"></textarea>
Script
$scope.requiredCheck = function () {
if(condition){
$scope.textRequired = false;
}else{
$scope.textRequired = true;
}
};
Note: I have simplified the answer

AngularJS binding checkboxes to model property

I have an AngularJS app with a list of users with an 'Edit' button beside each user. Each user has a number of subjects associated with them. When I click on 'Edit', it opens a form in which you can edit user details, and select associated subjects from a list of checkboxes. I'm trying to figure out how to bind the subject checkboxes so that the subjects which the
user is already associated with are checked, and the rest are unchecked. Any suggestions appreciated.
My HTML:
<form name="UserEditForm">
Name: <br /> <input type="text" name="name" ng-model="user.name"> <br />
{{name}}
Email: <br /> <input type="text" name="name" ng-model="user.email"> <br />
{{email}}
<div class="control-group">
<label class="control-label" for="inputSubjects">Subjects:</label>
<div class="form-group">
<label ng-repeat="subject in subjects" class="checkbox">
<input type="checkbox" ng-checked="{user.subjects}" name="selectedSubjects[]" value="{{subject.id}}" ng-model="subject.selected"> {{subject.name}}
</label>
</div>
<br />
<a ng-click="updateUser()" class="btn btn-small btn-primary">Save Changes</a>
</form>
My UserEditCtrl:
angular.module('myApp.controllers')
.controller('UserEditCtrl', ['$scope', '$routeParams','SubjectsFactory', 'UserFactory', '$location',
function ($scope, $routeParams, SubjectsFactory, UserFactory, $location) {
// callback for ng-click 'updateUser':
$scope.updateUser = function () {
$scope.user.subjects = $scope.selection;
UserFactory.update($scope.user);
$location.path('/users');
};
// callback for ng-click 'cancel':
$scope.cancel = function () {
$location.path('/users');
};
$scope.user = UserFactory.show({id: $routeParams.userid});
$scope.subjects = SubjectsFactory.query();
$scope.selection = [];
// helper method
$scope.selectedSubjects = function selectedSubjects() {
return filterFilter($scope.subjects, { selected: true });
};
// watch subjects for changes
$scope.$watch('subjects|filter:{selected:true}', function (nv) {
$scope.selection = nv.map(function (subject) {
return subject.id;
});
}, true);
}]);
As #jkinkead said, your code looks good, I fixed the ng-checked binding in accordance with your ng-model expression
Here's a simplified plunker : http://plnkr.co/edit/qaIBExtVbNdSXlQlbMym?p=preview
EDIT 1: I edited and improved the plunker to get closer to your case.

Categories