two-way binding in directive, model from service non-assignable - angularjs

I am getting the following error: "Expression '{0}' used with directive '{1}' is non-assignable!", as can be shown here: https://docs.angularjs.org/error/$compile/nonassign
Edit: Having moved the config object into the scope this part is resolved, however the models are still not bound as expected. http://plnkr.co/edit/AVs2IW75oWavpsPNDgnb?p=preview
Old plunker: http://plnkr.co/edit/AVs2IW75oWavpsPNDgnb?p=preview
(Try and edit a field and check the console)
I don't really understand the problem which is why that link can't help me to solve it. I am using a directive to bind data, and the data that is being "bound" is actually pointing to a service.
<multi-edit model="profileService.current" config="{
title: 'Edit profile description',
fields: [
{name: 'Title', model: profileService.current.title, input: true},
{name: 'Description', model: profileService.current.description, textarea: true}
]}">
CLick me
</multi-edit>
So I am trying to edit profileService.current.title for example, by using the ng-model config.fields[0].model. It can read the data correctly, but not write to it. What do I need to do in order to be able to write to the correct models?

UPDATED
You should use a scope model for "config".
Put this in your main controller:
$scope.config = {
title: 'Edit profile description',
fields: [{
name: 'Title',
model: 'title',
input: true
}, {
name: 'Description',
model: 'description',
textarea: true
}]
};
and then in your main HTML:
<multi-edit model="profileService.current" config="config">
CLick me
</multi-edit>
Then, in your directive HTML:
<li ng-repeat="(key, value) in config.fields">
<input ng-if="value.input" type="text" ng-model="model[config.fields[key].model]" />
<textarea ng-if="value.textarea" type="text" ng-model="model[config.fields[key].model]"></textarea>
</li>
See the updated plunker.

Related

How to share the same viewModel between two views in extjs?

Is it possible that two or more views in extjs share the same viewModel?
For example, if I have two views as presented in the code below, both views do not have the same view model, but instances of that viewModel. Maybe that was intention, but how to achieve to have global field that would be accessible across several views with the same declaration for viewModel.
So, I would like to bind the field name, so the change in one view automatically causes changes in all corresponding views.
Ext.define('MainModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.main',
data: {
name : '',
}
});
Ext.define('View1', {
extend: 'Ext.Container',
xtype: 'view1',
viewModel: {
type: 'main'
},
items: [{
xtype: 'textfield',
fieldLabel: 'Name:',
bind: {
value: '{name}',
}
}
]
});
Ext.define('View2', {
extend: 'Ext.Container',
xtype: 'view2',
viewModel: {
type: 'main'
},
items: [{
xtype: 'textfield',
fieldLabel: 'Name:',
bind: {
value: '{name}',
}
}
]
});
I don't think it is possible to do this they way you are asking. When you bind to a data element the system will first check the current components view model if it is does not find the value it will go up the parent and look and will continue this until it finds a match or there are no more parents. So if you want to share data in a view model you should store the data in a parent viewModel.
Here is a fiddle
The fields have two way binding so as you type in one it will update the view model and then the other field will be updated. On the fiddle edit each field and the other field will change. You can set either the property in the viewModel or either one of the two fields.
This fiddle shows setting the value of the field and the data in the parent viewModel via a button.

Angular JS - Select field not loading content when editing

I have a select field in AngularJs inside a ng-repeat:
HTML:
<span ng-repeat="lang in vm.formState.languageList track by $index">
<select ng-model="lang" ng-options="lang.name for lang in vm.langs">
<option value="">- Please Choose -</option>
</select>
</span>
Controller:
this.langs = [
{name: "English", id: "en"},
{name: "German", id: "ge"},
{name: "Spanish", id: "sp"},
{name: "French", id: "fr"},
...
];
formState.languageList is an array containing each lang object select by user in creation form, e.g. formState.languageList = [{name: "English", id: "en"}, {name: "Spanish", id: "sp"}]
My problem is: when I'm editing the form, I want the form fields (input, checkboxes, selects...) filled with current information. Everything works fine, except for select field.
How can I get this select fields loaded when editing the form?
Thanks in advance.
that is because you are facing the famous dot problem.
You can confirm it by change the ng-model to use $parent
ng-model="$parent.lang"
why it is not working is because ng-repeat is isolate scope directive.
the better way to solve it is use controllerAs syntax

how to bind angular to a single option object's property instead of an ng-model array for select multiple dropdowns

I am trying to use an angular binding on a select multi-select without using a main array to hold the values (most examples I see bind straight to the select tags via ng-options and ng-model, but I can't use a simple array to store the data right now outside of the options, but need to store if option is selected within the options themselves).
Here is an example of using ng-selected to initially select values based on a property 'selected' on the choice:
http://jsfiddle.net/armyofda12mnkeys/aLkLqqL6/3/
I was hoping I could add an ng-model="choice.selected" to the above code on the option tag (but that won't work as ng-model isn't meant to be used on an option tag).
Whats the best way to bind to each individual choice object?
Maybe a $watch of some sort or manual change event would work?
Thanks for any ideas/fiddle
P.S. the reason why I'm doing this is the model this is for is usually setup for 'grid' questions that have like 10 checkboxes going horizontally across the screen, and each choice sets its selected property like normal for a checkbox... But in mobile layouts, I switch the 'grid view' to be a native multi-select dropdown, which looks nicer on mobile, but it has to use the same model which I can't figure out.
var myApp = angular.module('myApp',[]);
var myApp = angular.module('myApp',[]);
myApp.controller("MyCtrl", function ($scope) {
$scope.main_question =
{
qid: 'QS1',
question_type: 'dropdown',
text: 'What country you from? ',
dropdownAnswer: 'CA',
choices: [
{option_value: 'US', option_txt: 'United States', selected: false},
{option_value: 'CA', option_txt: 'Canada', selected: true},
{option_value: 'MX', option_txt: 'Mexico', selected: false},
{option_value: 'DE', option_txt: 'Germany', selected: true},
{option_value: 'NN', option_txt: 'None of the Above (exclusive, should unset other options)', selected: false}
]
};
});
select {
height: 10em;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<div>
{{main_question.qid}}. {{main_question.text}}<br/>
<select
name="{{main_question.qid}}"
id="{{main_question.qid}}"
multiple="multiple"
>
<option value="" id="{{main_question.qid}}_not_picked">--Please Choose--</option>
<option
ng-repeat="choice in main_question.choices"
id="{{main_question.qid}}_{{choice.option_value}}"
ng-value="{{choice.option_value}}"
ng-selected="choice.selected"
>{{choice.option_txt}}</option>
</select>
</div>
<br/>{{main_question.choices}}
</div>
</div>
You can to use ng-click to invert the selection:
<option
ng-repeat="choice in main_question.choices"
id="{{main_question.qid}}_{{choice.option_value}}"
ng-selected="choice.selected"
ng-click="choice.selected = ! choice.selected"
>{{choice.option_txt}}</option>
Take a look at jsbin

AngularJS with Ionic, how to use ng-options

I recently started experimenting with AngularJS (and Ionic framework), and I just can't seem to get my dropdowns to work with an array of objects.
I can provide more code if needed, but basically I've got the following object in my controller:
$scope.availableCarParks = [{ 'Id': '1', 'Name': 'Parking1' },{ 'Id': '2', 'Name': 'Parking2' }];
And the following html markup:
<select ng-model="selectedCarPark" ng-options="cp.Name for cp in availableCarParks"></select>
For some reason, my dropdown is always empty...
When I do a "console.log(JSON.stringify($scope.availableCarParks))" the moment my controller gets initialized, I see a nice array of my objects like this (in chrome console):
[{"Id":"1","Name":"Parking1"},{"Id":"2","Name":"Parking2"}]
Am I doing anything wrong here? There must be something I'm overlooking...
You can use something like similar to this. Also I have used a default selected value as well.
inside the controller:
$scope.data = {
availableCarParks : [
{id: '1', name: 'Option A'},
{id: '2', name: 'Option B'},
{id: '3', name: 'Option C'}
],
//This sets the default value of the select in the ui
selectedOption: {id: '3', name: 'Option C'}
};
HTML Markup:
<select name="mySelect" id="mySelect"
ng-options="option.name for option in data.availableCarParks track by option.id"
ng-model="data.selectedOption"></select>
Hope this will help you..
Cheers!
Change your ng-option directive input to:
ng-options="co.Id as cp.Name for cp in availableCarParks"
Apparently, what went wrong was that my variable (availablecarparks) didn't have any values in it yet when the view was rendered.
I created a function in my app config and did a route resolve to make sure the api call happened before the controller showed the view, and all is well now.

Binding data with an angular-js ionic popup

I'm having weird issues that I can't seem to find an explanation for.
I show a popup with a single input which I am binding to a variable on my scope I'm passing the $scope to the popup.
The binding works and I can see the variable that is set and it changes as I type. But as soon as I close the popup and log out that scope variable on the "on tap" function" it seems to go back to its original value.
EDIT: a pen that demonstrated the general issue:
http://codepen.io/anon/pen/ariDh
code:
var sendPopup = $ionicPopup.show({
title: $translate.instant(popupTitle),
subTitle: $translate.instant('POPUP_WITH_MESSAGE_SUBTITLE'),
templateUrl: 'templates/leave-message-popup.html',
scope: $scope,
buttons: [
{ text: $translate.instant('BUTTON_CANCEL') },
{
text: $translate.instant('BUTTON_SEND'),
type: 'button-positive',
onTap: function(e) {
console.log("contact message:" + $scope.contactMessage);
if (!$scope.contactMessage) {
console.log("preventing default");
e.preventDefault();
} else {
$scope.sendData(contactType);
}
}
},
]
});
template:
<input type="text" ng-model="contactMessage" name="message" placeholder="{{'PLACEHOLDER_CONTACT_MESSAGE' | translate}}" required autofocus>
{{contactMessage}}
This amended version of your codepen shows this working: http://codepen.io/anon/pen/rgBLa
Changing the variable to an object that is on the scope that is passed to the popup correctly allows this to then be bound back to the controllers scope when it changes. This is needed due to the way the scope is managed when passed to the $ionicPopup.
$scope.contactMessage = { text: "text" }
Then updated the mark-up to correctly look at this property on the scope.
<input type="text" ng-model="contactMessage.text" name="message">
{{contactMessage.text}}
I hope this helps with your issue.

Resources