Update current model value while using bindings - angularjs

New to angular, so I hope I am asking this question correctly.
(Angular 1.5 and using components)
Parent.html:
<names on-refresh-names='$ctrl.reloadNames'></names>
Parent.js
this.reloadNames = function() {
...
}
Names.html
<input ng-model="searchNameValue">
<button ng-click='$ctrl.onRefreshNames()'></button>
Names.js
...
component.bindings = { onRefreshNames: '&' }
I want to make the input with the search string to be cleared (searchNameValue = '';) when the onRefreshNames is executed. But it is executed in the parent and the searchNameValue is in the child.
How can I do that?

You can combine statements into one expression:
<button ng-click="$ctrl.onRefreshNames(); searchNameValue = '';"></button>
But in this case it makes sense to move them both into a function in your component controller:
<input ng-model="$ctrl.searchNameValue">
<button ng-click="$ctrl.onRefresh()"></button>
where in controller
this.onRefresh = function() {
this.onRefreshNames()
this.searchNameValue = ''
}
In any case, note that in parent view it should be
<names on-refresh-names="$ctrl.reloadNames()"></names>

Related

AngularJs Component doesn't update view after img loading

i'm using angularJs 1.7 components.
This is my component who uploads a picture then converts it to base 64, then it is supposed to display it, but the displaying doesnt work .
myApp.component('club', {
templateUrl: 'vues/club.html',
controller: function($log,$scope) {
// HTML form data, 2 way binding ..
this.club = {};
// Bse 64 encoder
encodeImageFileAsURL = function() {
var filesSelected = document.getElementById("inputFileToLoad").files;
if (filesSelected.length > 0) {
var fileToLoad = filesSelected[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent) {
var srcData = fileLoadedEvent.target.result; // <--- data: convert base64 : OK
this.club.img = srcData ; // Displaying in view doesnt work
}
fileReader.readAsDataURL(fileToLoad);
}
}
// Jquery watcher when we upload a picture
$(document).on('change', 'input[type="file"]' , function(){
encodeImageFileAsURL();
});
This is the html button inside the template :
<div id="upload_button">
<label>
<input name="inputFileToLoad" id="inputFileToLoad" ng-model="logo" type="file" onchange="" /> </input>
<span class="btn btn-primary">Upload picture</span>
</label>
</div>
This is the error :
TypeError: this.club is undefined
srcData is ok, and holds a base 64 image, the function works well.
I've tried the solution provided (.bind(this)) there with no luck , i dont know where to place it:
How to access the correct `this` inside a callback?
When using the $scope syntax, it is working, adding $scope.$apply(), but now i'm using components based dev, and the .this syntax, it doesnt work any more .
EDIT 1 :
Ok, i've initialized club with
$scope.club = {} ;
then inside the function, i'm writing
$scope.club.img = srcData ;
Then, it is working ok. I dont understand why .this is not the same than $scope !
See following example for where this object has reference to
a={
firstname:"something",
lastname:"something2",
fullname:function(){
console.log(this.firstname+' '+this.lastname);
}
}
a.fullname();
In above example Object a is created and inside fullname() function this object pointing to 'a' Object.
So that in your case
templateUrl is only variable on this Object if you do not want to use $scope. You can declare it by using var club = {}

Angular 1.5 Components + ng-model $formatters and $parsers

I would like to know how to use $formatters and $parsers with angular 1.5 components. Can someone post an example.
Or is there something similar that I can use.
The following is an example of a component called example. This takes in a object that contains firstName and secondName. It then displays a combination of the firstName and secondName. If the object changes from the outside the formatter will fire followed by the render. If you want to trigger a change from the inside, you need to call this.ngModel.$setViewValue(newObject) and this would trigger the parser.
class example {
/*#ngInject*/
constructor() {}
// In the post link we need to add our formatter, parser and render to the ngmodel.
$postLink() {
this.ngModel.$formatters.push(this.$formatter.bind(this));
this.ngModel.$parsers.push(this.$parser.bind(this));
this.ngModel.$render = this.$render.bind(this);
}
// The formatter is used to intercept the model value coming in to the controller
$formatter(modelValue) {
const user = {
name: `${modelValue.firstName} ${modelValue.secondName}`
};
return user;
}
// The parser is used to intercept the view value before it is returned to the original source
// In this case we want to turn it back to it's original structure what ever that may be.
$parser(viewValue) {
// We know from out formatter that our view value will be an object with a name field
const namesParts = viewValue.name.split(' ');
const normalisedUser = {
firstName: namesParts[0],
secondName: namesParts[1],
};
return normalisedUser;
}
// This will fire when ever the model changes. This fires after the formatter.
$render() {
this.displayName = this.ngModel.$viewValue.name;
}
}
class ExampleComponent
{
bindings = {};
controller = Example;
require = {
ngModel: 'ngModel',
};
}
component('example', new ExampleComponent());
// Template for example component
<span>
{{ $ctrl.displayName }}
</span>
// Using the above component somewhere
<example ng-model="userModel"></example>

Show data in inputbox from 1 object and save it in using another object

I'm clicking a table row to edit the fields in a modal. The modal must have 2 functionalities (Add or Edit) depending on the GET request data like below.
$scope.editInterview = function(id) {
$http.get('/api/getinterview/' + id).then(function(response) {
editedObject = response.data.item
}
HTML
<label ng-if="editedObject.email">{{editedObject.email}}</label>
<label ng-if="!editedObject.email">Email</label>
<input ng-model="newObject.email" />
I am able to display the object in the labels, but that's not much help, because the data needs to be shown in the input boxes to be Edited and Saved.
How can i show the data from editedObject.email in the input, so i can save it using newObject.email?
I tried ng-init="editedObject.email", but it doesn't work. Is there some other ng-something that does this or i should be doing it in another way?
Update:
Edit and Update Methods, both are in the mainController.
$scope.editInterview = function(id) {
$http.get('/api/getinterview/' + id).then(function(response) {
editedObject = response.data.item
})
}
//Controller for the Modal
function DialogController($scope, $mdDialog, editedObject) {
$scope.editedObject = editedObject
$scope.submitObject = function(newObject) {
$http.post('/api/interview', newObject)
}
}
You have to make a deep copy from editObject.email to newObject.email. This could be done this way in controller after editOject.email has a value assigned.
$scope.newObject.email = angular.copy($scope.editObject.email);

Adding an active class on ng-click function

I have 2 buttons and I just want to add a class when the button has been clicked.
<button class="panel-btn"
ui-sref="basechat"
ng-click="setBaseChat()" id="base-chat-btn">Base Chat</button>
<button class="panel-btn"
ui-sref="banner"
ng-click="setBannerChat()"
id="banner-chat-btn">Banner</button>
The function on ng-click returns a true value.
Hope you guys can help me, I still don't understand very well how ng-class works
If you want to add a class to a button on click you can do something like this:
<button ng-class="{someClass: someTruthyValue}" ng-click="someFunction()">
The ng-class will look at the value of someTruthyValue and display someClass if it is True, and not otherwise.
For example, your JS could look something like:
$scope.someTruthyValue = False;
$scope.someFunction = function() {
$scope.someTruthyValue = True;
}
The docs are fairly good here
Also, as you can see in the other answers, there is more than 1 way to use ng-class, however I like my solution because it allows you the option to link additional button to reverse the class change:
<button ng-click="someReverseFunction()">
Where, certainly:
$scope.someReverseFunction = function() {
$scope.someTruthyValue = False;
}
As a simple example, you could have:
$scope.bannerClass = "baseClass"; // baseClass defined in your CSS
$scope.setBannerChat = function() {
$scope.bannerClass = "myClass"; // myClass defined in your CSS
// or $scope.bannerClass = "baseClass myClass";
}
and then:
<div ng-class="bannerClass">Hello</div>
<button ng-click=setBannerChat()></button>
You can do this in your controller:
$scope.clickFucntion = function(){
$scope.myClass = 'my-class';
}
and this in your view:
<button class="{{myClass}}" ng-click="clickFucntion()">

How can I make angularjs ngChange handler be called only when user finishes typing

I have an input field, where I want to apply the variant of ngChange.
The input field is sort of binding with an ajax call, when user changes the input, the server side will process the data, however, I don't wanna make the call too often.
Say the user wanna input a really string, I want the call be made only after user finishes the word he is about to type.
Nevertheless, I don't wanna use event such as blur. What would be a better way to implement this, rather than setTimeout?
Use ng-model-options in Angular > 1.3
<input type="text"
ng-model="vm.searchTerm"
ng-change="vm.search(vm.searchTerm)"
ng-model-options="{debounce: 750}" />
Without ng-model-options -- In markup:
<input ng-change="inputChanged()">
In your backing controller/scope
var inputChangedPromise;
$scope.inputChanged = function(){
if(inputChangedPromise){
$timeout.cancel(inputChangedPromise);
}
inputChangedPromise = $timeout(taskToDo,1000);
}
Then your taskToDo will only run after 1000ms of no changes.
As of Angular 1.3, you could use Angular ng-model-options directive
<input ng-change="inputChanged()" ng-model-options="{debounce:1000}">
Source: https://stackoverflow.com/a/26356084/1397994
Write your own directive- this will only run the commands on myText based on the conditions you set
<input my-change-directive type="text ng-model="myText" />
.directive('myChangeDirective',function() {
return {
require : 'ngModel',
link : function($scope,$element,$attrs) {
var stringTest = function(_string) {
//test string here, return true
//if you want to process it
}
$element.bind('change',function(e) {
if(stringTest($attrs.ngModel) === true) {
//make ajax call here
//run $scope.$apply() in ajax callback if scope is changed
}
});
}
}
})

Resources