I have a list of inputs, created by:
<div ng-controller="MainCtrl">
<div ng-repeat="variable in variables">
<label>{{ variable.slug }}</label>
<input type="text" ng-model="variable.value" ng-change="variableChange()" />
</div>
</div>
And a controller:
function MainCtrl($scope) {
$scope.variables = [
{'slug':'background', 'value':'#666'},
{'slug':'foreground', 'value':'#999'}
]
}
I'm using the less.js to compile the less in the browser, and I want to be able to re-compile it when the variable changes - something like inside the controller:
$scope.variableChange = function() {
less.modifyVars({ variable.slug : variable.value });
};
But I get the error:
ParseError: Unrecognised input in preview-style.less on line 102, column 1:
102#variable.slug: variable.value;
But if I remove the apostrophes for the variables, I get an angular error:
Bad Argument: Argument 'MainCtrl' is not a function, got undefined
Can anyone help with this?
Edit: here's the less.modifyVars() function if it helps:
less.modifyVars = function (a) {
var b = "";
for (var c in a) b += ("#" === c.slice(0, 1) ? "" : "#") + c + ": " + (";" === a[c].slice(-1) ? a[c] : a[c] + ";");
less.refresh(!1, b)
}
If you are writing inside the controller, you must address a scoped property with $scope:
$scope.variableChange = function() {
less.modifyVars({ $scope.variable.slug : $scope.variable.value });
};
But that will not get this example to work because of the ng-repeat.
It would be better to pass the object to the function:
<div ng-controller="MainCtrl">
<div ng-repeat="variable in variables">
<label>{{ variable.slug }}</label>
<input type="text" ng-model="variable.value" ng-change="variableChange(variable)" />
</div>
</div>
And then call less like this:
$scope.variableChange = function(selectedVariable) {
less.modifyVars({ selectedVariable.slug : selectedVariable.value });
};
Related
I am working with AngularJS and I am trying to pass a value from the Angular into the Controller. This is what my AngularJS Script File looks like:
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
{
function startTime() {
var today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
// add a zero in front of numbers<10
m = checkTime(m);
s = checkTime(s);
return (h + ":" + m + ":" + s);
t = setTimeout('startTime()', 500);
}
$scope.name = startTime();
}
});
</script>
So from that I am able to get the time through calling $scope.name. But I want to pass that variable into the controller. The way I was thinking of doing it was to pass it in an Html.BeginForm as a parameter but that's not working. This is my BeginForm:
<div ng-app="myApp" ng-controller="myCtrl">
#using (Html.BeginForm("Bob", "Home", new { Time = ng-model="name" },
FormMethod.Post, null))
{
<p>Name:</p> <input style="color:black;" ng-model="name">
<h1 style="color:black;">You entered: {{name}}</h1>
<button type="submit" style="color:black;">Submit</button>
}
</div>
Right now I have the input box there just so I could make sure that it's passing the right value, and it is. But in the BeginForm it's not allowing Time to equal the value being passed from the AngularJS. How would I be able to pass that value to the Controller?
You could pass it as a hidden field:
#using (Html.BeginForm("Bob", "Home", FormMethod.Post))
{
<input name="time" type="hidden" ng-value="name" />
<button type="submit" style="color:black;">Submit</button>
}
With the code below, the age2 doesn't get updated even though age changes.
<div ng-app="myApp" ng-controller="myController">
<input type="text" ng-model="age" placeholder="Name"></input>
<input type="text" ng-model="firstName" placeholder="First name"></input>
<h1>Hi there, {{ firstName }}, you are {{ age }} year old, age2 is {{ age2 }}!</h1>
var app = angular.module('myApp', []);
app.controller('myController', function($scope){
$scope.age = 20;
$scope.age2 = parseInt($scope.age) + 1;
});
Could anyone tell me what's wrong with it? If I change age2 to a function:
{{ age2() }}
$scope.age2 = function(){return parseInt($scope.age) + 1};
it's working well though. I know that Angular checks if the value has changed, if it stays the same in two consecutive 'checks' then it updates the view. If it takes too long, then probably the values will be changing forever and it throws an error (from what I've understood).
There are a few ways of dealing with it.
Using a watcher:
$scope.$watch('age', function(newVal, oldVal) {
$scope.age2 = parseInt(newVal) + 1;
})
Using a function in the controller:
$scope.parseAge = function(age) {
return parseInt(age) + 1
}
{{ parseAge(age) }}
Or using a filter:
app.filter('parseAge', function() {
return function(input) {
return parseInt(input) + 1;
}
});
{{ age | parseAge }}
To directly answer the question:
In the first case you are only assigning the value of age2 when the controller first initializes. There is no inheritance or watch that would ever change that value.
When it is a function called in the view it will get re-evaluated each digest.
If you are working with a simple operation like what you have you could also do the addition in the view among numerous other ways to make it work
{{ +age +1 }}
Below, summary and test are set via MyCtrl. I'm seeing "my test" display properly, but not "summary.name". I'm seeing that MySvc.get()'s callback executes as expected, but summary.name's updated value doesn't appear on the UI.
Any suggestions on why summary.name's updated value isn't appearing on the UI ?
app.js:
...
.state('tab.edit', {
url: '/edit',
views: {
'tab-dash': {
templateUrl: 'templates/MyTemplate.html',
controller: 'MyCtrl'
}
}
})
...
MyTemplate.html:
<label class="item item-input item-stacked-label">
<span class="input-label">Name</span>
<textarea rows="8" placeholder="Nothing yet." ng-model="summary.name"></textarea>
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">TEST</span>
<textarea rows="8" placeholder="Nothing yet." ng-model="test"></textarea>
</label>
controllers.js:
...
.controller('MyCtrl', function($scope, MySvc) {
console.log("MyCtrl: entered");
$scope.summary = MySvc.get(0);
$scope.test = "my test";
...
MySvc.get(0) returns ( and I see this callback execute and change ret.name ):
return $http.get(url).then(function(response) {
console.log("MySvc callback: response.data = %o", response.data);
console.log("MySvc callback: response.data.name = " + response.data.name);
ret = new MySvc(response.data);
console.log("MySvc callback: ret.name = " + ret.name);
return ret;
});
You treated the return value of MySvc.get as a synchronous (immediately available) value. What is received via the $http service is not available immediately, so you can't treat it as a simple return value.
What you'll really want to do is use it as a promise, which it (most likely) is:
MySvc.get(0)
.then(function(summary) {
$scope.summary = summary;
});
And you'll probably want to read up on promises, Chapters 1 to 3 of "You Don't Know JS - Async & Performance" are an excellent starting point.
I want to do something similar to (in my html):
{{ Customer.Name }}
when Customer.Name is
"{{ Customer.FirstName + ' ' + Customer.LastName }}"
How can I achieve this? The Customer.Name-String is a dynamic configuration that I read from the server. I would like to do this on several places in my application so I don't want a static code-behind-function that does this for me.
All I want is that Angular evaluates the expression recursively.
You can use the method $eval() of $scope to achieve this.
For example, your Controller would define your customer object like this:
function TestCtrl ($scope) {
$scope.customer = {
firstname : 'Darth',
lastname : 'Vader',
name : 'customer.firstname + " " + customer.lastname'
};
$scope.ev = $scope.$eval;
}
Then in your view you could use the configuration string like this:
<h1 ng-controller="TestCtrl">Hello {{$eval(customer.name)}}!</h1>
It is important that your customer.name property does not contain the curly brackets!
See this plunkr for a working example: http://plnkr.co/edit/r524cP6OAOBBzDReLNw4?p=preview
There are 2 way to do it.
Create a directive that use a customer object and concatenate both First and Lastname.
angular.module('customer.directives',[]).
.directive('customerName', function() {
restrict : 'EA', // both element and attr will work in case you are using a customer directive
replace : true,
scope : {
Customer : '='
},
template : '{{Customer.FirstName}} {{Customer.Lastname}}'
});
Example Call :
<div ng-repeat="Customer in Customers">
<customer-name='Customer'></customer-name>
</div>
Or you could use a function inside the CustomerService to send your controller the full name already concatenated.
Ex :
angular.module('Customer.Services', [])
.factory('CustomerService', function(){
return {
/* other methods here */
getFullName : function(Customer) {
return Customer.FirstName + ' ' + Customer.LastName
}
}
});
angular.module('Customer.Controllers', [])
.controller('CustomerController', function($scope.CustomerService) {
$scope.service = CustomerService.query();
$scope.getFullName = fucntion(customer) {
return CustomerService.getFullName(customer);
}
}
)
And call it with :
<div ng-repeat="Customer in Customers">
{{getFullName(Customer)}}
</div>
I am stil new to Angular, but trying, very hard, to get my head round it.
Basically, I just want to move from one view, to another one function is complete. Here is the code:
App.controller('clientLogin', function ($scope, $http, $route) {
$scope.clientLoginBt = function () {
var sun = $('#ClientUsername').val();
var spa = $('#ClientPassword').val()
$http({url: "/sources/",
headers: {"X-Appery-Database-Id": dbid},
params: {where: '{"$and" : [{"username": "' + sun + '"}, {"password" : "' + spa + '"}]}'}})
.success(function (data) {
console.log(data.length);
$scope.clientLogggedin = data;
if (data.length > 0) {
$route.clientLogggedin();
} else {
}
})
.error(function (status) {
console.log('data on fail: ' + status);
});
}
});
Above, if the data comes back with more than one row, the user log is correct, and I just want to change view!
I have tried $location, did not work, and as Angular is really simple to use, in the amount of coding, I cannot see any info on it, other than if you click, it starts a controller.
Here is the HTML:
<div class="row" ng-controller="clientLogin">
<div class="large-12 medium-12">
<input type="text" id="ClientUsername" placeholder="Enter Username" />
<input type="password" id="ClientPassword" placeholder="Enter Password" />
<button ng-click="clientLoginBt()">Login</button>
</div>
</div>
The page I am looking to jump to, within the is called clientLoggedIn.html.
I have also added it to the config, thinking i could access it with $route :
App.config(function ($routeProvider) {
$routeProvider
.when('/',
{
templateUrl: 'views/home.html'
})
.when('/userLogin', {
templateUrl : 'views/userLogin.html',
controller: 'userLoginController'
})
.when('/clientLogin', {
templateUrl : 'views/clientLogin.html',
controller: 'clientLoginController'
})
.when('/clientLoggedIn', {
templateUrl : 'views/clientLoggedIn.html',
controller: 'clientLoggedInController'
})
.otherwise({
redirectTo : '/'
}
);
});
Any ideas on what I am doing wrong please ?
Thanks in advance.
Using path method of $location should do the trick. Since you want to get to clientLoggedIn.html, you would need to use the matching route (/clientLoggedIn):
$location.path("/clientLoggedIn");
Be sure that $location service is injected into your App Controller. This is the line you should probably replace with what I have above:
$route.clientLogggedin();
It is just a matter of checking an indicator whether the $http call was successful or not. If you are not willing to add a routing for clientLoggedIn.html. You can do something like below, just to enable the logged in page:
<div class="row" ng-controller="clientLogin">
<div class="large-12 medium-12" ng-hide="sucessfulLogin">
<input type="text" id="ClientUsername" placeholder="Enter Username" />
<input type="password" id="ClientPassword" placeholder="Enter Password"/>
<button ng-click="clientLoginBt()">Login</button>
</div>
<ng-include src="'views/clientLoggedIn.html'" ng-show="sucessfulLogin">
</ng-include>
<!-- or just include the DOM element here if you do not
want a separate html altogether-->
</div>
and in the REST call:
if (data.length > 0) {
//Assuming the flag in pre-initialized to false in controller
$scope.sucessfulLogin = true;
} else {
}
Also note, using ng-include directive you can still use a separate controller in clientLoggedIn.html if you are willing to. Just have to use ng-controller in the first element inside clientLoggedIn.html.