I'm working on a mini-project to brush up on my Angular but it seems I forgot more than I thought. I'm using 2 components weather-search and display-weather and they communicate through the HomeController. Now, what happens is this, when I enter a value (either city or zip) and submit the form, the console will log the return with the JSON data from the API, but it won't display in the UI unless the form is re-submitted then it will update with the search result, essentially, every second submit will update the UI. Why? :(
app.js
var angular = require('angular')
angular.module(`weather_app`, [])
.controller('HomeController', function(){
this.data = ''
})
require('./services/index')
require('./components/weather-search')
require('./components/display-weather')
weather-search.js
angular.module('weather_app')
.component('weatherSearch', {
templateUrl: './templates/weather.html',
bindings: {
weather: '&'
},
controller: WeatherSearchController
})
function WeatherSearchController(WeatherService, CountryService){
var ctrl = this
ctrl.title = "Weather App!"
ctrl.searchWeather = function(data) {
// ...
WeatherService.getCurrent(data.option, data.value)
.then( result => {
// ...
ctrl.weather({$event: {data: result}})
})
.catch( error => {
console.error(error)
})
}
}
display-weather.js
angular.module('weather_app')
.component('displayWeather', {
template:`
Display: {{ $ctrl.weather }}
`,
bindings: {
weather: '<'
}
})
weather.pug
div(class="weather")
h1.
{{ ::$ctrl.title }}
div(class="weather-search")
form
select(ng-init="weather.option = weather.option || 'zip'", ng-model="weather.option")
option(value="zip").
Zip Code
option(value="city").
City
input(class="weather-search-input", ng-model="weather.value")
select(ng-init="weather.type = weather.type || 'f'", ng-model="weather.type")
option(value="f").
Fahrenheit
option(value="c").
Celsius
option(value="k").
Kelvin
button(type="submit", ng-click="$ctrl.searchWeather(weather)").
Search
div(ng-if="$ctrl.error", class="error").
{{ $ctrl.error }}
Related
i'm trying to get data from my api, the code for getting datas :
getList() {
this.fileList = [];
this._globalService.getUserFiles(this.userId)
.then(files => {
files.forEach(retFile => {
this._globalService.getFileActions(retFile._id)
.then(retActions => {
this.fileList.push( {
file: retFile,
action: retActions
});
});
});
})
.finally(() => {
this.finish = true;
});
}
Call OnInit hook.
After, my view is trying to show same that :
<ng-container *ngIf="finish; else wait">
<ng-container *ngIf="fileList.length; else noItems">
<li *ngFor="let item of fileList">
...
</li>
<ng-container>
<ng-template #noItems>
<span class="noItems">Any file</span>
</ng-template>
<ng-container>
That works fine.
But my problem lasts a few seconds the #noItems template is to show when datas exists, like in this example :
You always push your result into this.FileList, you this.FileList never empty, therefore your noItem template never show up.
I am using a custom view directive inside a ng-repeat list like this:
//Directive
app.directive("card", function () {
return {
restrict: "E",
templateUrl: "views/card.html"
};
});
...
//List
<card ng-repeat="card in cards = main.data.getCards() | filter: sidebar.search() | orderBy: ['isPinned',$index]:true track by $index"
ng-if="content.checkCard(card)">
</card>
main.data is a reference to a service, where the data is being stored.
Here is a simplified version:
app.service('data', function ($http, engine) {
var cards = [];
...
return {
getCards: function () {
return cards;
},
setCards: function (data) {
cards = data;
engine.save("cards", cards);
},
When the data changes through the setCards() method, my list shows only empty elements. If I use the exact same html code inside my ng-repeat directly however, everything works fine. What can I do?
I'm new to Ionic. I write code for list. List is working perfectly but when click on any list-item it's not showing any data.
It showing me this error "Cannot GET /pilliondetails/1" how can i solve this?
app.factory('myService', function() {
var savedData = {}
function set(data) {
savedData = data;
console.log(savedData);
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
})
PillionList Controller:
.controller('PillionListCtrl',function($scope,$ionicHistory,myService){
$scope.myGoBack = function() {
$ionicHistory.goBack();
};
$scope.pillions = [];
var promise=myService.get();
$scope.pillions=myService.get();
})
PillionDetail Controller:
.controller('PillionDetailCtrl',function($scope, $ionicHistory, $stateParams, myService)
{
$scope.myGoBack = function() {
$ionicHistory.goBack();
};
var promise=myService.get($stateParams.requestId);
console.log(promise);
})
PillionList.html :Showing list pf Pillions
<ion-list>
<ion-item data-ng-repeat="pillion in pillions">
<div class="list list-inset">
{{pillion.request_departure_date}}-{{pillion.request_departure_time}}
{{pillion.request_from}} >> {{pillion.request_to}}
{{pillion.user_first_name}} {{pillion.user_last_name}}
<a ui-sref="pilliondetails({pillionId:pillion.request_id})" nav-direction="enter">
<h2>More Details...</h2>
</a>
</div>
</ion-item>
</ion-list>
my app.js
.state('pillionlist', {
url: '/pillionlist',
templateUrl: 'templates/pillionlist.html',
controller: 'PillionListCtrl'
})
.state('pilliondetails', {
url: '/pillionlist/:pillionId',
templateUrl: 'templates/pilliondetails.html',
controller: 'PillionDetailCtrl'
})
Its redirecting to pillionDetail view but not showing data.
Please help.
The first thing i noticed is
ui-sref="pilliondetails({pillion.request_id})"
it should be key-value pair like this
ui-sref="pilliondetails({ your_id : pillion.request_id})"
and in stateProvider, the url of details page should contain parameter. for eg.
url : '/pilliondetails/:your_id'
I want to implement 'edit' feature to any book, but I can't get my book.
How it works now:
I click on the any record (which is <tr>).
I am being redirected to the books_edit state
This 'edit' page must have all the data in form of current book (but it doesn't).
So, the question is: How can I pass book from the books state to books_edit state and submit it correctly?
HTML piece:
<tr ng-click="bookCtrl.editBook(book)" ng-repeat="book in bookCtrl.books">
<td>{{ book.name }}</td>
<td>{{ book.author }}</td>
<td>{{ book.price }}</td>
<td>{{ book.pubdate | date }}</td>
<td>{{ book.coverUrl }}</td>
<td>{{ book.pagesCount}}</td>
</tr>
States:
.state('books_new', {
url: '/books/new',
templateUrl: 'books/book_new.html',
controller: 'BookCtrl as bookCtrl'
})
.state('books_edit', {
url: '/books/edit',
templateUrl: 'books/book_edit.html',
controller: 'BookCtrl as bookCtrl'
})
.state('books', {
url: '/books',
templateUrl: 'books/books.html',
controller: 'BookCtrl as bookCtrl'
})
Controller's methods:
editBook: function(book) {
if (book) {
console.log(book); // logs correct book
$state.go('books_edit'); // tried to send `book` as a parameter, didn't work
}
},
submitBook: function(book) {
if (book) {
console.log(book);
return books.$save(book).then(function(data) {
$state.go('books');
});
}
}
Edit snippet:
<form class="container col-lg-3" ng-submit="bookCtrl.submitBook(book)">
<div class="input-group">
<label class="col-sm-2 control-label">Назва:</label>
<input type="text" ng-model="book.name" class="form-control">
I've tried to send book as a parameter in state, but no result.
The best way to handle this, is to be 'stateless'. This way a user can bookmark the edit page, and reload the page without requiring any state to be present in the app.
Pass the id of the book you want to edit as a url parameter to the edit state, like so:
state config:
.state('books_edit', {
url: '/books/edit/:bookId',
templateUrl: 'books/book_edit.html',
controller: 'BookCtrl as bookCtrl'
})
controller:
$state.go('books_edit', {bookId: book.id});
In the edit controller, fetch the book using the id from the url, using the $stateParams service:
angular.module('myapp').controller('BookCtrl', function($scope, $stateParams){
//fetch the book id from the url params
var bookId = $stateParams.bookId;
//now get the book with the given id
});
I would advise to use a separate controller for the edit functionality, i.e. do not use 'BookCtrl' for every view.
Define state parameters as following
$stateProvider.state('books_edit', {url: '/books/:bookId',params: {obj: null},templateUrl: 'books/books_edit.html',controller: 'booksCtrl'})
when calling pass parameter like this:
$state.go('books_edit',{obj: myobj});
In controller you can receive parameter using
$state.params.obj
Hope it helps.
You can use a service to reach this. Create a service where you can set/get the value and inject in both controllers. The service looks like this:
app.service('bookService', function() {
var books = [];
var addBook = function(obj) {
books.push(newObj);
};
var getBook = function(){
return books;
};
return {
addBook: addBook,
getBook: getBook
};
});
And, in controller:
editBook: function(book) {
if (book) {
// ensure to inject productService in controller
bookService.addBook(book)
console.log(book); // logs correct book
$state.go('books_edit'); // tried to send `book` as a parameter, didn't work
}
},
In book_edit controller:
.....
// ensure to inject productService in controller
$scope.book = bookService.getBook(book)
....
You can also use $broadcast, read more:
On and broadcast in angular
Hope it helps
Try passing it in state.go as something like this "books/" and then use state params to retrieve it.
state('books_edit', {
url: '/books/edit:bookID',
templateUrl: 'books/book_edit.html',
controller: 'BookCtrl as bookCtrl'
})
submitBook: function(bookID) {
if (bookID) {
console.log(bookID);
return books.$save(bookID).then(function(data) {
$state.go('books/'+<bookID>);
});
}
}
in the Controller
editBook: function($scope, $stateParams) {
$scope.bookID = $stateParams.bookID;
}
Thanks #fikkatra and #Gurpinder for helping with this! The complete solution is following:
Add this to the books_edit state:
params: {data: null}
In the editBook() function send parameters to the next state:
$state.go('books_edit',{bookId: book.$id, data: book});
Add this to the bookCtrl - bookCtrl.currentBook = $state.params.data;
Change ng-model in the view to bookCtrl.currentBook.KEY_NAME
I'm writing an angular 1.5.0-rc0 application using bootstrap for a nav bar component.
I want to show the user an added items to his navigation bar if his user group id is 1.
first I created a service:
app.factory('UserService', function() {
return {
userGroupId : null
};
});
I created the nav bar as a directive, so i included it in the main html file
<nav-bar></nav-bar>
and the nav-bar directive code:
(function () {
angular.module('myalcoholist').directive('navBar', function () {
return {
restrict: 'E',
templateUrl: 'views/nav.html',
controller: ['$scope','$auth', 'UserService',function ($scope,$auth,UserService) {
$scope.user=UserService;
$scope.isAuthenticated = function()
{
return $auth.isAuthenticated();
};
}]
}
});
})();
as you can see I set $scope.user as the returned object from UserService.
in my login controller, after a successful login I set the userGroupId.
angular.module('myalcoholist').controller('LoginController',['$scope','$auth','$location', 'toastr','UserService',function ($scope,$auth,$location,toastr,UserService) {
$scope.authenticate = function (provider) {
$auth.authenticate(provider).then(function (data) {
var accessToken = data.data.token;
apiKey=accessToken;
UserService.userGroupId=data.data.user_group_id;
...
now.. my nav-bar template file is as the following code:
<li ng-show="user.userGroupId == 1">
Admin Drinks
</li>
even after the authentication, when I uset userGroupId to 1 the element is still not shown.
any ideas?
update
I debugged and noticed that UserService.userGroupId is still null. so
I changed the UserService to have the following code:
app.factory('UserService', function() {
var user = {userGroupId:null};
return {
setUserGroupId: function (userGroupId) {
user.userGroupId=setUserGroupId;
},
getUserGroupId: function () {
return user.userGroupId;
}
};
});
in my LoginController I now try to execute setUserGroupId:
angular.module('myalcoholist').controller('LoginController',['$scope','$auth','$location', 'toastr','UserService',function ($scope,$auth,$location,toastr,UserService) {
$scope.authenticate = function (provider) {
$auth.authenticate(provider).then(function (data) {
var accessToken = data.data.token;
apiKey=accessToken;
UserService.setUserGroupId(data.data.user_group_id);
...
when I debug i see that userService is an object with two functions as I defined, but when the javascript chrome debugger tries to execute this line:
UserService.setUserGroupId(data.data.user_group_id);
I get the following error:
ReferenceError: setUserGroupId is not defined
at Object.setUserGroupId (app.js:21)
at login-controller.js:12
at angular.js:15287
at m.$eval (angular.js:16554)
at m.$digest (angular.js:16372)
at m.$apply (angular.js:16662)
at g (angular.js:11033)
at t (angular.js:11231)
at XMLHttpRequest.v.onload (angular.js:11172)
I have created a fiddle showcasing your requirement (as close as possible), and it seems to work fine.
http://jsfiddle.net/HB7LU/21493/
My guess is that you aren't actually setting the value when you think you are, and will likely require some debugging. Here is the code for brevity.
HTML
<div ng-controller="MyCtrl">
<div ng-click="clicked()">
Click ME, {{user.value}}!
</div>
<test-dir></test-dir>
</div>
JS
angular.module('myApp',[])
.service('TestService', function(){
return {
value: 2
};
})
.directive('testDir', function(){
return {
restrict: 'E',
template: '<div ng-show="user.value === 1">Here is some text</div><div>Some more always showing</div>',
controller: function ($scope, TestService) {
$scope.user = TestService;
}
};
})
.controller('MyCtrl', function($scope, TestService){
$scope.user = TestService;
$scope.clicked = function(){
TestService.value = 1;
};
});