I've a simple Web App with 2 html pages, see below :
index.html
<div ng-controller="ThirdCtrl">
<h2> {{titre}}</h2>
<form>
<input type="text" ng-model="test"><br>
<button ng-click="toSend()">OK</button>
</form>
</div>
indexv2.html
<div ng-controller="ThirdCtrl">
<h2>{{titre}}</h2>
{{test}}
</div>
app.js
var app = angular.module('myApp', []);
app.controller('ThirdCtrl', function($scope, $window){
$scope.titre = "ThridCtrl";
$scope.test = "";
$scope.toSend= function()
{
$window.location.href = "http://localhost:10080/ClientAngular/indexv2.html";
}
});
I'm trying to send data when button is clicked to an other page, redirection is working to indexv2.html but I can't to get my data "test". The data "titre" is weel displayed but not "test".
Do you know how can I to get a data after ng-click function ?
Thanks in advance.
I think he wants to move data between pages - I had a similar situation which I'm still working on - just that he is not showing us enough code. Say you get a visitor's input data on a web form and need to display that data to another web page where you then send to a back-end server from the subsequent page, but all this using angularjs, how do you get that done?
Further you say get the value for 'titre' right on the subsequent page but not for 'test'. I think it is because 'test' has not been set - except otherwise you are not showing enough code.
Related
I have an ionic app set up with 3 tabs (Tab1, Tab2 Tab3) and an ion-list with ion-items in each tab, with different data loaded.
If I open any one of the tabs initially (as in navigating to it from the address bar) they each work. But if I'm on the Home tab and switch to the Search tab, the ion-list doesn't appear. Similarly, if I start on the Search tab and go to the Home tab, the ion-list doesn't appear in the home tab.
The nav bar and tab bar do appear. It just doesn't show the ion-content.
The DOM is infact populated with the data. ion-content contains the ion-list with the ion-items with the HTML and data I want. They just for some reason don't visually appear (elements wit size and width of 0 as if they were empty)
If I resize the Safari window on desktop, the content suddenly appears perfectly.
Also If I start on one tab, switch to another, and then switch back, the content also appears perfectly.
The problem only occurs when testing in Safari on the desktop or in the app on iOS. Testing in Chrome and desktop and running the app on Android run it fine.
If I hardcode sample data and add it to the same array the ng-repeat uses the hardcoded data appears in the DOM correctly. Only when resizing the window or switching tabs makes the rest of the data appear.
The rest of the data is loading using $http.get()
Simple clicking and scrolling appear to not do anything. Only a page resize or switching tab makes the AJAX loaded data appear.
Calling $scope.$apply() or $scope.$digest don't appear to do anything.
The troubleshooting and debugging mentioned above makes me think its a bug with Ionic and/or AngularJS in rendering asynchronously loaded data. I'm wondering if anyone has a solution or work-around to this.
Relevant code:
Controller
angular.module('starter.PostListPlaceView', [])
.controller('PostListPlaceViewCtrl', function($scope, $http, PostFactory, Constants, $rootScope, $sce, linkify, SinglePostService, $stateParams, $timeout) {
function sendGetInitialPostsRequest(){
$http.get(Constants.GET_POSTS_URL, {params : paramObject})
.then(function (response){
$scope.posts = [];
for(var i = 0; i < response.data.resultsArray.length; i++){
var post = new PostFactory(response.data.resultsArray[i]);
console.log(post.desc);
}
$timeout(function() {
$scope.$digest();
console.log("$scope.$apply() called.");
}, 0);
$scope.$broadcast('scroll.refreshComplete');
$scope.$broadcast('scroll.infiniteScrollComplete');
});
}
});
Template:
<ion-content>
<ion-refresher pulling-text="Pull to refresh" on-refresh="doRefresh()">
</ion-refresher>
<ion-list>
<div ng-repeat="post in posts track by $index">
<ion-item class="post wrap" >
<div class="post-desc" ng-bind="post.desc"></div>
</ion-item>
</div>
</ion-list>
<ion-infinite-scroll on-infinite="getPosts()" distance="1%" ng-if="moreResults &&!loading">
</ion-infinite-scroll>
</ion-content>
As mentioned above, this code works perfectly in Chrome on desktop and Android, so I don't think its a logical/syntax error in my code itself.
Solved this by upgrading from Ionic 1.1.1 to Ionic 1.2
PLUNKER
I'm developing an AngularJS SPA, using ng-route and ng-animate. I'm trying to display the Bootstrap Carousel on the index.html#/ using ng-show. Very simple task.
I want the Carousel to show on the index page, but not on the about page or the contact page.
I'm trying to do the logic in my indexController like so:
if ($location.path() == "/") {
$scope.isIndexPage = true;
}
And in my HTML:
<div id="myCarousel" class="carousel slide" data-ride="carousel" ng-show="isIndexPage">
But it does not work as expected: the Carousel does not display. Once the ng-show attribute is removed, the carousel displays, but on all pages.
How can I get the Carousel to display only on the index page? I've tried variations such as ng-include-ing and ng-ifing carousel.htm. Numerous Google searches such as "AngularJS SPA and Bootstrap Carousel" reveal unanswered SO questions.
Thanks in advance for any input. Here's the PLUNKER.
It's a bit strange not to put something that is specific to the home page into the template of the home page, but anyway...
Your code has 2 main problems:
you're trying to access a variable from the indexController scope from a part of the page that is not controlled by this controller. The controller only controls its view. The $scope of the controller is limited to its view.
You're initializing the isIndexPage variable only once. It never changes after.
Solution:
create a controller for the whole body of the page, and put the logic used to control the visibility of the carousel in that controller
use a function that will return true or false based on the current location
See http://plnkr.co/edit/8luxeIbyIPEKy0LkemM0?p=preview for a fork of your plunker (the additional JS code is at the end of script.js):
appname.controller('MainCtrl', function($scope, $location) {
$scope.isIndexPage = function() {
return $location.path() === '/';
}
});
and in the index.html file:
<body ng-controller="MainCtrl">
<div ng-show="isIndexPage()" ...>
Hello im working on a web app project, and we are using jquery mobile for the pages ui and angular for mvc reasons,
Im having a problem using my external pages ( pages that ive load to my index.html), they dont recognize my controllers (only works the controllers that ive put in the index.html)
ill some of my code here to explain my problem
if ive put some angular values in my external page (previews declaration of the controller in my
<div data-role="page" id="ResEjecSuc" class=".paginas"
data-dom-cache="true" ng-controlles="categController" >
)
<span ng-class="sucursal.TIT_CATEGORIZACION">
{{sucursal.TIT_REALIZADA}}</span>
my app only shows: {{sucursal.TIT_REALIZADA}}
my controller init code :
app = angular.module('nevadaProt', [])
app.controller('categController', controlerCateg)
controlerCateg = function($scope, $locale) {
var sucursal = {
TIT_CATEGORIZACION:4,
TIT_REALIZADA:12
}
how ive load and after that transition to my html page:
Load:
$.mobile.pageContainer.pagecontainer("load",
"pages/RappidApps2/ResumenEjecZona.html", {});
transition:
$.mobile.pageContainer.pagecontainer("change", "#ResEjecSuc", {
transition : "pop",
reverse : false
});
how can i make work angular controllers and external jquery mobile pages?
Once you are using Angular, you may create a directive.
app.directive('externalHtml', function(){
return {
restrict : 'E'
,replace : true
,templateUrl : 'pages/RappidApps2/ResumenEjecZona.html'
};
});
then, you html should be something like:
<body>
<div data-role="content">
<external-html/>
</div>
</body>
It always works for me.
Suppose I've got following elements on the same page:
Filters panel (something similar to
http://www.imdb.com/search/name)
Items based on filter options
I want to implement following logic:
URL should contain applied filter data in path (/appliedOptionA/appliedOptionB)
When user opens site app get filter data from URL, updates filter
panel and items panel
When user changes filters app updates URL and refreshes items
First idea: configure ng-router, get filter data as param, convert data to model, construct filters panel, load items, construct items panel. Main problem: how should it work when user changes filter? If I'll update URL it will trigger same controller with different param and repeat the process -> get filter data as param, convert data to model, construct filters panel, items and so on. I don't need it - my model and UI is already up to date.
My question:
what is the correct way to keep model and URL synchronized? Should URL manage model (ng-route) or model changes manage URL (how?) ?
My recommendation would be to use angular-ui-router and use that instead of ng-router since angular-ui-router gives you much more flexibility and is, in my opinion, easier to use.
Given your "Main Problem", it sounds like you want to have an single application controller (let's refer to this as the "appCtrl") handle all changes and make the necessary changes to its model. The main drawback with this approach is it forces you to the maintain the "filteredItems" model within the appCtrl, which is not fun and could lead to unnecessary headaches. An easier way to approach it would be to have another controller deal with those changes to the url, rather than the appCtrl itself. That being said, let me show you how you could accomplish this.
*WARNING: The post is very long! (but hopefully helpful) *
Because of this, I have also created a demo of everything I am about to discuss in case you "just want teh codez":
http://plnkr.co/edit/IMZZTE?p=preview
http://run.plnkr.co/fUddH83P2orHUsWj/#/
Creating the application
Since we are creating a brand new application, let's start with creating and configuring the application.
NOTE: Remember to load in the angular-ui-router script into your application and add the dependency.
app.js
var myApp = angular.module('myApp', ["ui.router"]);
Now that we have the app, let's add it to the index.html using the ngApp directive.
index.html
<body ng-app="myApp"></body>
With the application in place, let's look at the issues you addressed in your question:
URL should contain applied filter data in path (/appliedOptionA/appliedOptionB)
When user opens site app get filter data from URL, updates filter panel and items panel
When user changes filters app updates URL and refreshes items
What you want to do is create a state. Essentially, a state is activated/deactivated based on the url pattern. Given a particular pattern, you can tell the application how to act (using a controller) and what to look like (using a template). Before continuing, make sure to reference url routing, which will help with url patterns.
We need to:
give the state a name ("filteredItems")
provide a url pattern
provide a controller
provide a templateUrl
Let's configure the application, as well as:
provide a default url route in the event the url does not exist
add a default home state
add the filteredItems state
app.js
myApp.config(function($stateProvider, $urlRouterProvider){
// default url - used if url pattern is not recognized
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', { // default state
url: '/'
})
.state('filteredItems', { // give the state a name
url: "/:appliedOptionA/:appliedOptionB", // provide the url pattern
controller: 'FilteredItemsCtrl', // controller to use for this state
templateUrl: "filteredItems.html" // url for the template
});
});
We have now configured the state's url to take parameters (appliedOptionA and appliedOptionB). Using $stateParams service, we can create a filteredItemsCtrl and have that be responsible for filtering out the data.
But before we do that, we should create a service. When using Angular, AVOID using controllers to maintain data since they can be created/destroyed. Best practice is to use services instead. That being said, let's create an amazing itemService:
itemService.js
angular.module('myApp').factory('itemService', itemService);
function itemService (){
var items = {
appliedOptionA: [ 'Item 1', 'Item 2', 'Item 3' ],
appliedOptionB: [ 'Item 4', 'Item 5', 'Item 6' ]
};
function getItems (){
return items;
}
return {
getItems: getItems
}
}
Gorgeous right? I am glad you think so too!
Now that we have a service, we can create the FilteredItemsCtrl. Let's also inject our newly created itemService into the FilteredItemsCtrl, so its able to access the data.
NOTE: Remember to inject the $stateParams service as a dependency!
filteredItemsCtrl.js
angular.module('myApp').controller('FilteredItemsCtrl', filteredItemsCtrl);
filteredItemsCtrl.$inject = ['$stateParams', '$scope', 'itemService'];
function filteredItemsCtrl ($stateParams, $scope, itemService){
var items = itemService.getItems(); // get items from service
// filter items
$scope.appliedOptionA = items.appliedOptionA.filter(function (item){
if ($stateParams.appliedOptionA){
return item.toLowerCase().indexOf($stateParams.appliedOptionA) > -1 ||
item.indexOf($stateParams.appliedOptionA) > -1
}
});
$scope.appliedOptionB = items.appliedOptionB.filter(function (item){
if ($stateParams.appliedOptionB){
return item.toLowerCase().indexOf($stateParams.appliedOptionB) > -1 ||
item.indexOf($stateParams.appliedOptionB) > -1
}
});
}
When we defined our state's url, we set it up like: url: "/:appliedOptionA/:appliedOptionB". This means the $stateParams will be populated with appliedOptionA, appliedOptionB properties. Also this means every time the URL changes, a new filteredItemsCtrl is created, thus, you do not have to maintain the application's model!
Before we forget, we also need to create a template for this state.
filteredItems.html
<div>
<div>
<span>Filtered Option A Items:</span>
<ul>
<li ng-repeat="optionItemA in appliedOptionA">
{{ optionItemA }}
</li>
</ul>
</div>
<div>
<span>Filtered Option B Items:</span>
<ul>
<li ng-repeat="optionItemB in appliedOptionB">
{{ optionItemB }}
</li>
</ul>
</div>
</div>
With the state, filteredItemCtrl, and view created, all that is left is to include the ui-view directive, in order for the state's template to properly appear:
index.html
<body ng-app="myApp"
ng-controller="MyAppCtrl">
<div>
<div>
Applied Option A: <input ng-model="appliedOptionA" />
</div>
<div>
Applied Option B: <input ng-model="appliedOptionB" />
</div>
<button type="button"
ng-click="filter()">Search</button>
</div>
<!-- where the state template goes -->
<div ui-view></div>
</body>
That is all there is to it! Sorry about the long post, but hopefully you found this informative! Please let me know if you have any issues!
When you want the search keywords to be reflected in the URL (so they can be bookmarked and addressed directly), I would recommend not to force every change of the model (which would be after every keystroke), but wait for a submit of the form. Then you rewrite the URL (via $location.path and/or $location.search) and the ngRoute will kick in.
NgRoute will (re)load/refresh the page as if it were the first time, and that matches the idea of a directly addressable page that includes search keywords. I would not recommend getting the data as soon as you get the submit, because as you stated, ngRoute will refresh the page.
In my web application i start feeling the need to pass objects from one page controller to another, not just parameters in the route. I think that this can make my application faster and the code clean. By page controllers i mean controllers corresponding to $routeProvider routes.
I think i can easily implement this with a service, say pageBroker. This service will take a route and an object, and load the page corresponding to the route:
pageBroker.load('/assign-task/', { task: { ... } });
That page would find the object in a special section of the service:
pageBroker.pageData.task;
Page data can be reset for every route change.
This is not an implementation problem, but a software design problem. Usually similar questions get closed on Stack overflow, but i will try once again: is this a good or a bad idea? Is it suitable for the Angular architecture? Why yes or why not?
From my experience with AngularJS, I would say using Services is a good approach, always worked well for me. (But if anyone thinks differently, I will be more than happy to hear your thoughts on this)
var myApp = angular.module('myApp', []);
myApp.factory('Data', function() {
return {message: "I'm data from a service and I can be shared between multiple controllers"}
})
function FirstCtrl($scope, Data){
$scope.data = Data;
}
function SecondCtrl($scope, Data){
$scope.data = Data;
}
and in your view you can use it like
<div ng-app="myApp">
<div ng-controller="FirstCtrl">
<input type="text" ng-model="data.message">
<h1>{{data.message}}</h1>
</div>
<div ng-controller="SecondCtrl">
<input type="text" ng-model="data.message">
<h1>{{data.message}}</h1>
</div>
</div>
You can even bind the Data.message to a model in the controller scope and whenever you change the model, the data-binding will change also on the Service and consequently on the other Controller (But sometimes you might need to call $apply).
This video might be useful to you: https://egghead.io/lessons/angularjs-sharing-data-between-controllers