angular/ionic - model does not update $scope in controller - javascript

I am a newb with angularjs and I am trying something that I believe should be very simple ... but turns out I am not figuring it out.
I have a $scope variable that I want to double bind (using ng-model) to a textarea. I was able to make it work on js fiddle websites but now on my code. I have tried to strip everything down to just a few lines and it still doesn't work, the controller is never updated.
this is my code:
js/main.js
var app=angular
.module('noclu', ['ionic', 'app.controllers'])
.config(function ($stateProvider, $urlRouterProvider){
$stateProvider
.state('menu.main', {
url: "/main",
views: {
'menuContent': {
templateUrl: 'templates/main.html',
controller: 'MainCtrl'
}
}
});
$urlRouterProvider.otherwise("/menu/main");
});
js/controller.js
angular
.module('app.controllers', [])
.controller('MainCtrl', function ($scope){
$scope.src='---';
$scope.get_feeds=function(){
//seems like that here "this" is actually the textarea ??
//$scope.src is always whatever has been set in the controller
console.log('this:'+this.src); //this output whatever I enter in the textarea
console.log('scope:'+$scope.src); //this always output '---'
};
});
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<link rel="icon" type="image/png" href="favicon.png">
<title>NoClu</title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/main.js"></script>
<script src="js/controllers.js"></script>
</head>
<body ng-app="noclu">
<ion-nav-view></ion-nav-view>
</body>
</html>
template/main.html
<ion-view view-title="NoClu" >
<ion-content class="padding" id="src-wrapper-center">
<div ng-class="vertical_center">
<div id="src-wrapper">
<div>
<div class="padding src-title">What are you in the mood for ?</div>
<div class="item" id="src-txt-wrapper">
<textarea id="src" ng-model="src"></textarea>
</div>
<button id="search" class="button button-block button-large button-balanced" ng-click="get_feeds()" >
Let's eat
</button>
</div>
</div>
</div>
</ion-content>
</ion-view>
UPDATE - I made it work, but why ?
I made it work by changing $scope.src='---'; to $scope.src={body:'---'}; and then changing the ng-modal to src.body. but.. WHY did not work the other way as it works for boolean?

Using directly $scope. is not a good practice in angularJS. There are various post of it, more concernign $scope inheritence.
For exemple : http://learnwebtutorials.com/why-ng-model-value-should-contain-a-dot
Therefore, your need to change your model like that :
$scope.myModel = {};
$scope.myModel.src = "---"
And your html to bind to myModel.src

Related

How to create an Angular JS Material Element via a JavaScript Function?

Problem: I have created a webpage with an md-card that has a button. Upon clicking that button, I want another card to appear. The Problem: I cannot figure out, how to make the button of the new card work. It is not correctly formated and it has no functionality.
Question: What do I need to change the code to, to make it work? Thanks.
Code: This is my JavaScript-Code:
angular.module('MyApp', ['ngMaterial', 'ngMessages', 'material.svgAssetsCache'])
.controller('AppCtrl', function($scope, $mdDialog) {
function addMeinElement () {
// create a new div element
var newDiv = document.createElement("md-card");
document.querySelector('#myID').appendChild(newDiv);
newDiv.innerHTML = "<md-card-content>Oh no! Why does this button not work?<br>"+
"<md-button class='md-warn' ng-click='my_print_to_console()'>Button :( </md-button>"+
"</md-card-content>";
}
$scope.my_print_to_console = function () {
addMeinElement ();
};
});
This is the corresponding html:
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://www.gstatic.com/firebasejs/5.8.4/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.8.4/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.8.4/firebase-firestore.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic">
<link rel='stylesheet' href='https://cdn.gitcdn.link/cdn/angular/bower-material/v1.1.13/angular-material.css'>
<link rel='stylesheet' href='https://material.angularjs.org/1.1.13/docs.css'>
</head>
<body>
<div ng-controller="AppCtrl" ng-app="MyApp">
<div style="position:fixed; width:100%; top:0; height:100%;">
<div style="position:fixed;width:80%;top:0;left:50%;transform: translate(-50%, 0);">
<md-card>
<md-card-content>
<p>Click the button to hopefully create a new card with another button.</p>
<md-button class="md-warn" ng-click="my_print_to_console()";>Button :)</md-button>
</md-card-content>
</md-card>
<div id="myID">
</div>
</div>
</div>
</div>
<!--
Copyright 2018 Google LLC. All Rights Reserved.
Use of this source code is governed by an MIT-style license that can be found
in the LICENSE file at http://material.angularjs.org/HEAD/license.
-->
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.7.6/angular.js'></script>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.7.6/angular-animate.min.js'></script>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.7.6/angular-route.min.js'></script>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.7.6/angular-aria.min.js'></script>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.7.6/angular-messages.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.js'></script>
<script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-114/svg-assets-cache.js'></script>
<script src='https://cdn.gitcdn.link/cdn/angular/bower-material/v1.1.13/angular-material.js'></script>
<script src="app.js"></script>
</body>
It happens because Angular not aware that this is a an Angular component. you need to wrap your HTML with $compile service.
Add '$compile' to your module dependency
Wrap the code like that
$compile('your html here')($scope);

Unable to load the Module in Angularjs?

Hi I am developing Angularjs Application. I am using UI Router. This is my First Angular project and I am facing issues. I am running Index page. Index page contains header and footer. In body i am trying to bind views on page load.
Below is my Index.html
<html ng-app="RoslpApp">
<head>
<!--Angularjs and ui routing-->
<script data-require="angular.js#1.4.5" data-semver="1.4.5" src="https://code.angularjs.org/1.4.5/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.8/angular-ui-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.4.2/angular-ui-router.min.js"></script>
<!--Angularjs and ui routing-->
<!--Arebic Translation-->
<script data-require="angular-translate#*" data-semver="2.5.0" src="https://cdn.rawgit.com/angular-translate/bower-angular-translate/2.5.0/angular-translate.js"></script>
<script src="scripts/angular-translate.js"></script>
<script src="scripts/angular-translate-loader-partial.min.js"></script>
<!--Arebic Translation-->
<!--Date Picker-->
<link href="App/CSS/angular-datepicker.css" rel="stylesheet" />
<script src="App/JS/angular-datepicker.js"></script>
<!--Date Picker-->
<!--Toaster-->
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i,800,800i" rel="stylesheet">
<script src="https://unpkg.com/angular-toastr/dist/angular-toastr.tpls.js"></script>
<link rel="stylesheet" href="https://unpkg.com/angular-toastr/dist/angular-toastr.css" />
<!--Toaster-->
<!--SPA Files-->
<script src="App/App.js"></script>
<!--SPA Files-->
</head>
<body ng-controller="RoslpAppController">
<header>
<div class="logo"><img src="App/images/logo.png"></div>
</header>
<!--inject here-->
<div class="container">
<div ui-view></div>
</div>
<footer>
</footer>
This is my App.js
var app = angular.module('RoslpApp', ['pascalprecht.translate', 'ui.router', 'toastr', '720kb.datepicker']);
app.config(function ($stateProvider, $urlRouterProvider, $translateProvider, $translatePartialLoaderProvider)
{
$urlRouterProvider.otherwise('/HomePage');
$stateProvider
.state('ForgotPassword.ChangePasswords', {
url: '/ForgotPasswordChangePasswords',
templateUrl: 'ForgotPassword/ChangePassword.html',
params: {
LoginID: null
},
controller: 'ChangePasswords'
})
.state('HomePage', {
url: "/HomePage",
templateUrl: "Registration/HomePage.html"
});
});
app.controller('RoslpAppController', ['$scope', '$translate', 'toastr', function ($scope, $translate, toastr) {
//toastr.success('Hello world!', 'Toastr fun!');
$scope.clickHandler = function (key) {
$translate.use(key);
};
}]);
This is my HomePage.html
<div class="banner-container">
</div>
When i load my page first time, I am getting below error.
Uncaught Error: [$injector:nomod] Module 'RoslpApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
May I know why I am facing below mentioned issues. Thanks in advance.
There are no references in the index.html for pascalprecht.translate ,ui.router, 'toastr', '720kb.datepicker'
Add the necessary references. And the references to your app.js also missing!
You need to add your js script in your html
<html ng-app="RoslpApp">
<head>
</head>
<body ng-controller="RoslpAppController">
<header>
<div class="logo"><img src="App/images/logo.png"></div>
</header>
<!--inject here-->
<div class="container">
<div ui-view></div>
</div>
<footer>
</footer>
<script src="app.js"></script>
<script src="my_other_js.js"></script>
</body>
</html>

Angular 'undefined is not a function' defining component

I had working ionic code to allow the user to input a list, which I tried to factor out into a component for re-use. But on running I get the error undefined is not a function in line 4 of the js. How can this be fixed?
/*jshint multistr: true */
var app = angular.module('ionicApp', ['ionic']);
app.component('inputlist',{
bindings: {label: '#'},
template: '\
<div class="list">\
<div class="item item-button-right">\
<ion-label floating>Enter {{$ctrl.label}} below then press +</ion-label>\
<input type="text" ng-model="nameinput.name"></input>\
<button class="button button-assertive" ng-click="addItem()">+</button>\
</div>\
<div class="item item-button-right" ng-repeat="item in items track by $index">\
<ion-label>{{item.name}}</ion-label>\
<button class="button button-positive" ng-click="items.splice($index,1)">-</button>\
</div>\
</div>',
controller: function() {
this.items = [];
this.nameinput = {name:''};
this.addItem = function(){
var name = this.nameinput.name.trim();
if (name!=="")
{
this.items.push({name:name});
this.nameinput={name:""};
}
};
}
});
html
<!DOCTYPE html>
<html ng-app="ionicApp">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title>Ionic-AngularJS-Cordova</title>
<!-- Ionic framework - replace the CDN links with local files and build -->
<link href="lib/ionicframework/ionic.min.css" rel="stylesheet">
<script src="lib/ionicframework/ionic.bundle.min.js"></script>
<script src="js/app.js"></script>
<script src="cordova.js"></script>
</head>
<body>
<ion-content>
<inputlist label="foo"></inputlist>
</ion-content>
</body>
</html>
You mentioned that you are using Ionic v1.0.0-beta1 in your project, which i believe that this version of ionic comes bundle with angular version below 1.3.
Component, on the other hand, is a new feature available in angular 1.5 and above. This explains why you got function is undefined in line 4 app.component() method.
I would suggest you to take either one of these 2 approach to resolve your issue:
1) Convert component to directive.
2) Upgrade the ionic to v1.3.2 (latest version) which supports angular 1.5

Multiple controllers working within ngRoute example

I have a small ngRoute example I am trying that to use multiple applications and controllers with. The first app/controller is for the main page, while the second set of app/controller is for the html that ngRoute loads up after pressing a button. However, it doesn't seem to be working. Code below:
Main Module
var app = angular.module("MainModule", ["ngRoute"]);
Main Controller
app.controller("MainController", function ($scope) {
});
app.config(function ($routeProvider) {
$routeProvider
.when('/customers', {
templateUrl: "customers.html",
controller: "CustomerController"
})
});
Customer Module
var CustomerModule = angular.module("CustomerModule", []);
Customer Controller
CustomerModule.controller("CustomerController", function ($scope) {
$scope.Test = "Hey";
$scope.CustomerArray = [
{ "firstName" : "John", "lastName" : "Williams", "Occupation" : "Fireman" },
{ "firstName" : "Louis", "lastName" : "Abrams", "Occupation" : "Policeman" }
]
});
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-route.js"></script>
<script src="scripts/MainModule.js"></script>
<script src="scripts/MainController.js"></script>
<link rel="stylesheet" type="text/css" href="MyCSS.css">
</head>
<body>
<div ng-app="MainModule">
<div id="TopDiv">Main Module</div>
<input type="button" value="Load Customers" />
<div ng-view></div>
</div>
</body>
</html>
customers.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="scripts/CustomerModule.js"></script>
<script src="scripts/CustomerController.js"></script>
</head>
<body>
<div ng-app="CustomerModule" ng-controller="CustomerController">
{{Test}}
<ul>
<li ng-repeat="x in CustomerArray">{{x.firstName x.lastName x.Occupation}}</li>
</ul>
</div>
</body>
</html>
Long bits of code there, but hopefully simple code. The output when I press the "Load Customer" button is literally {{Test}} with no array data to follow.
I am just now learning angular, so any help with this issue I would appreciate. I am just doing this for fun, to try to learn. So I suppose the issue is not pressing. :) Thanks!
I wrote out a working example using the code from the question as a base. There are quite a few adjustments that were made, so I will list each piece with a bit of explanation.
It is not necessary for each "page" to have it's own module. However, it is not a bad practice. To support the design you have here of one module for each view, I made the following changes:
Include the CustomerModule as a dependency in the MainModule (MainModule.js):
var app = angular.module("MainModule", ["ngRoute", "CustomerModule"]);
Load ALL scripts in the index.html:
<script src="scripts/MainModule.js"></script>
<script src="scripts/MainController.js"></script>
<script src="scripts/CustomerModule.js"></script>
<script src="scripts/CustomerController.js"></script>
With these changes, the $routeProvider is able to locate the CustomerController and instantiate it during a route change. The customers.html now does not have to create a controller, and can be stripped down to a complete partial. Also, the expression used in customers.html needed to be changed, and broken down into individual expressions for each property.
The final customers.html:
{{Test}}
<ul>
<li ng-repeat="x in CustomerArray">{{x.firstName}} {{x.lastName}} {{x.Occupation}}</li>
</ul>
Complete working sample on plnkr.co: http://plnkr.co/edit/EjwW9Fsc2DPhBejUETwB?p=preview
I'm not sure, but the problem is in your MainModule. It should be like this or so:
var app = angular.module("MainModule", ["ngRoute"]);
When you calling angular.module with only one parameter - it's only trying get module, not create.
And customers.html should only contains parts of you html, not full:
Full customers.html
{{Test}}
<ul>
<li ng-repeat="x in CustomerArray">{{ x.firstName }} {{ x.lastName }} {{ x.Occupation }}</li>
</ul>
And add move customer js files to index.html:
<script src="scripts/MainModule.js"></script>
<script src="scripts/MainController.js"></script>
<script src="scripts/CustomerModule.js"></script>
<script src="scripts/CustomerController.js"></script>
<link rel="stylesheet" type="text/css" href="MyCSS.css">
Hope, it helps.

How to properly setup AngularJS files

Im familiar with the standard way of setting up a angularjs project, what I'm trying to do is set the app with separate files for different controllers and directives based on the page. See below for better explanation.
www /
app.js
index.html
login /
loginDirective.js
loginPage.html
This is my apps.js file
// Ionic Starter App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
(function () {
'use strict';
angular.module('app', ['ionic']);
})();
var app=angular.module('app');
app.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
if(window.cordova && window.cordova.plugins.Keyboard) {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
// Don't remove this line unless you know what you are doing. It stops the viewport
// from snapping when text inputs are focused. Ionic handles this internally for
// a much nicer keyboard experience.
cordova.plugins.Keyboard.disableScroll(true);
}
if(window.StatusBar) {
StatusBar.styleDefault();
}
});
})
this is my loginDirective.js
(function () {
'use strict';
var app=angular.module('app');
app.config(function($stateProvider) {
$stateProvider
.state('login', {
url: '/login',
template: '<loginDirective></loginDirective>'
})
})
app.directive('loginDirective', loginDirective);
function loginDirective() {
var directive = {
restrict : 'EA',
templateUrl : 'loginPage.html',
controller : loginController,
controllerAs : 'lg',
bindToController : true
};
return directive;
}
function loginController() {
var lg = this;
lg.test = 'this is a test';
console.log('RETURN = %s', 'test');
}
})();
this is my index.html
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
<script src="login/loginDirective.js"></script>
</head>
<body ng-app="app" animation="slide-left-right-ios7">
<div>
<div>
<ion-nav-bar class="bar-dark">
<ion-nav-title>Sample APP</ion-nav-title>
<ion-nav-back-button class="button-icon icon ion-ios-arrow-back">Back</ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view ></ion-nav-view>
</div>s
</div>
</body></html>
last but not least loginPage.html
<html>
<head>
</head>
<body>
<div login-directive></div>
<ion-view view-title="Login" name="login-view" class="scroll-bg" hide-nav-bar="true">
<ion-content class="padding">
<div align="center" class="imagecontent">
<div style="text-align: center">
<img ng-src="img/logos#2x.png" width="250px">
</div>
</div>
<div class="list list-inset">
<label class="item item-input">
<input type="text" placeholder="Username" style="color: #ffffff" ng-model="data.username">
</label>
<label class="item item-input">
<input type="password" placeholder="Password" style="color: #ffffff" ng-model="data.password">
</label>
</div >
<div class="" >
<div class="">
<button class=" button button-block button-dark" ng-click="login(data)">LOG IN</button>
</div>
</div>
</ion-content>
<div style="position: absolute; bottom: 10%; width: 100%">
<div style="text-align: center">
<img ng-src="img/FNC_Logo.png" width="150px">
</div>
</div>
<ion-footer-bar align-title="right" class="footer-bg">
<div class="col text-right" ng-click="doSomething()">
<button class="button footerbtn-bg" ></button>
</div>
</ion-footer-bar>
</ion-view>
</body>
</html>
What am I doing incorrectly that causes my loginPage.html to not show up?
I may be wrong, because I a novice with AngularJS, but if I were you, I firstly would try to change:
templateUrl : 'loginPage.html'
into:
templateUrl : 'login/loginPage.html'
I came to such conclusion, because you included loginPage.js file in index.html, so it tries look loginPage.html in www directory, or in directory where it was called.
I met such case like yours today, but with images.
You state definition has problems:
$stateProvider
.state('login', {
url: '/login',
//This should be kebab-case
template: '<login-directive></login-directive>'
//NOT camelCase
//template: '<loginDirective></loginDirective>'
})
})
But I am not sure why you are using a directive for that state when you could define the state with a controller:
.state('login', {
url: '/login',
templateUrl : 'loginPage.html',
controller : loginController,
controllerAs : 'lg'
});
Try moving <div login-directive></div> into the ion-view.
Also inspect the console to see if console.log('RETURN = %s', 'test'); is actually outputted. At least you'd then know if the state is active or not.
Like #georgeawg said, you're overcomplicating this by using a directive as template. Why you did that in this example is beyond me. Also, your $state config should be in your app.js file.

Categories

Resources