in my app I have ng-repeat loop, where I from another list select media and push it to array medias. But for every media, I can input custom duration (from media list in object I get predefined media duration, but if we want we can set our custom duration)
<div ng-controller="MyCtrl">
<div ng-repeat="media in medias">
<span>{{media.title}}</span><br>
<input ng-model="media.duration" /><br><br>
</div>
<button ng-click="getInputValue(media.title, media.duration)">Get</button>
</div>
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.medias = [{
title: 'res1',
duration: 25.2
},
{
title: 'res2',
duration: 15.00
}
];
$scope.getInputValue = function(title, duration) {
alert(title); //undefined
alert(duration); //undefined
}
}
Here is jsfiddle
And, on submit I need to take all custom changed duration and send it to API.
The first problem is, in my GET button value is undefined.
This button needs to be outside from ng-repeat div because I have another data on the page for sending.
I try to put ng-init, but this fire on load and after nothing.
Also, I try ng-change, but I have the same name for ng-model (because it's dynamically) and with this, I don't know which item I changed.
Idea is, when user change duration for media he wants, on submit I get data and put them in an array like this:
//get passed data from ng-repeat
var mediaCustomDuration = [];
$scope.getInputValue = function(title, duration) {
mediaCustomDuration.push({
mediaID: title,
mediaDuration: duration
});
//do stuff ...
}
}
ng-click="getInputValue(media.title, media.duration)"
is out of repeat scope so this values (media.title and ...) are always undefined
So here it is two solutions:
On click you need to iterate over your medias ($scope.medias) and collected data you need. Ng-model insures that your custom duration will be set into the media object and you can pick it and send to server.
Another one
Make button type="submit"
Create directive on form ng-submit="submit($scope.medias)"
In $scope.submit take medias (they will be already changed) and post them to the remote.
That is all
Hope this helps.
Related
I have an html page, which has two fields From date and To date. On clicking the submit button I'm able to retrieve the information based on the dates and display it,in the same page but my From date and TO date fields become empty. So how do I hold the values so that they are retained in their respective fields even after the displaying the information.
HTML:
<ion-content ng-init=onViewloaded()>
From:
<input type="date" ng-model="fromDate">
To:
<input type="date" ng-model="toDate">
<button type="submit" ng-click="Save()">Submit</button><br>
Data:
{{receivedData.name}}
{{receivedData.information}}
</ion-content>
Controller:
$scope.receivedData;
$scope.onViewloaded=function()
{
bulkDateService.getData($scope.RetrievedData);
}
$scope.RetrievedData = function(data,error)
{
$scope.receivedData=data;
}
$scope.save=function()
{
var dataToSend={'from':$scope.fromDate, 'to':$scope.toDate};
bulkDateService.postData(dataToSend,error);
}
So what am I missing to do, in-order to display the From date and To date in their fields even after loading the data?
Since you are passing the objects by references in var dataToSend={'from':$scope.fromDate, 'to':$scope.toDate};, probably they are getting deleted or changed inside theis function bulkDateService.postData(dataToSend,error); (when you alter the field 'to' and 'from' of dataToSend.
To try this out, send a copy of the dates instead of the reference and see if that fixes your problem. Like this:
var dataToSend={'from':angular.copy($scope.fromDate), 'to':angular.copy($scope.toDate)};
And try to avoid ng-init directive, keep controller logic away from view whenever you can. For this you can simply call the function on the controller:
$scope.onViewloaded=function()
{
bulkDateService.getData($scope.RetrievedData);
}
$scope.onViewloaded();
Or even better, use ionic's view events: Ionic Docs
$scope.$on("$ionicView.beforeEnter", function(event, data){
$scope.onViewloaded();
});
I have a customer who is a member of a web site. He has to fill a form every time which is really very often. That's why he wants me to develop an application for him to make this process automatic. When I use the webBrowser control to manipulate it, I am able to login but after that there are fields that contains data-binding. These fields are the ones I need to manipulate. When I push the data to necessary fields, it's not working, because in the html tag, there is no value attribute, instead it has data-binding. So my question is how can I manipulate and push data to these fields?
Thank you so much for your all help in advance.
Knockout uses data-binds to listen to changes in an input and update an underlying model. For example, the value binding listens to change events and writes the new value to a data-bound observable.
If you update a value attribute through code, the change event isn't triggered. You'll see the new value in the UI, but the javascript model won't be updated.
You can combat this by explicitly triggering a change. Here's an example:
Type in the input: you'll see a console.log that shows knockout gets updated
Press the button to inject a new value: you won't see a log: knockout isn't updated
Press the last button to trigger a change event. You'll notice knockout now updates the model.
Of course, you can combine the two click listeners into one function. I've separated them to get the point across.
// Hidden knockout code:
(function() {
var label = ko.observable("test");
label.subscribe(console.log.bind(console));
ko.applyBindings({ label: label });
}());
// Your code
var buttons = document.querySelectorAll("button");
var input = document.querySelector("input");
buttons[0].addEventListener("click", function() {
input.value = "generated value";
});
buttons[1].addEventListener("click", function() {
// http://stackoverflow.com/a/2856602/3297291
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
input.dispatchEvent(evt);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="text" data-bind="value: label">
<button>inject value from outside</button>
<button>let knockout know something changed</button>
I have a simple typeahead for a list of currencies. When I start typing and I select the desired value (or hit TAB on that), the desired value is selected - until this point everything works as desired.
However, if I type the entire word and click outside the input instead of selecting the value (onblur event), then even if the value inside my input matches the filter value, the selected scope variable doesn't update, so my input is invalid. What I'm trying to do is to overwrite the selected value during onblur event.
Example: If I type EUR without hitting TAB or selecting the EUR value from the typeahead dropdown and then click outside the input, the EUR text stays inside the input, but selected value is undefined. I want the selected value to hold EUR instead of undefined. I used $viewValue to send the input value during onblur event.
The HTML:
<input type="text" ng-model="selected" typeahead-editable="false" typeahead="currency for currency in currencies | filter:$viewValue" ng-blur="selectCurrency($viewValue)" />
<div>Selected: {{selected}}</div>
The JavaScipt:
angular.module('myApp', ['ui.bootstrap'])
.controller("mainCtrl", function ($scope) {
$scope.selected = '';
$scope.currencies = ['EUR', 'GBP', 'USD'];
$scope.selectCurrency = function(test) {
console.log(test); //outputs undefined instead of EUR
//if (checkIfCurrencyExists(test, $scope.currencies)) { - will do the checks later
$scope.selected = test;
//}
};
});
In the JsFiddle below you can see the same scenario, except it has US states instead of currencies. Try to type in Alabama then left click outside the input (don't TAB and don't select the state), you'll see that the selected scope variable stays empty
JsFiddle link here.
Found another solution - setting both typeahead-select-on-exact and typeahead-select-on-blur attributes to true:
<input typeahead-select-on-exact="true" typeahead-select-on-blur="true" uib-typeahead=...
Typeahead-select-on-exact makes the exactly matching item automatically highlighted in the list, and typeahead-select-on-blur makes the higlighted item selected on blur.
If you want to select the first result from the typeahead list on blur, then you can set typeahead-select-on-blur="true" in your input field as given in the doc.
typeahead-select-on-blur (Default: false) - On blur, select the
currently highlighted match.
Found an answer myself at the time, but forgot to answer my question here.
Added this to the directive:
data-ng-blur="blur($event)"
And this is the function:
$scope.blur = function(e) {
var inputCurrency = e.target.value.toUpperCase();
angular.forEach($scope.currencies, function(currency) {
if (currency === inputCurrency) {
$scope.field = currency;
}
});
};
I spend some time searching for similar question and made a lot of testing untill I got it working. I can see that in answers there is a solution but I try to summarize it so it could be a bit more clear.
In typeahead part include:
<input type="text" ng-model="selected" typeahead-editable="false" typeahead="currency for currency in currencies | filter:$viewValue" ng-blur="checkSelectedValue()" typeahead-select-on-blur="true" />
First part includes validation function of your scope value (you don't need to pass the value as it's the $scope.selected and you can use it in your controller): ng-blur="checkSelectedValue()".
Thus include in your controller:
$scope.checkSelectedValue = function() {
if (code that check if $scope.selected in range of allowed values) {
$scope.inputValid=true; //you can use this scope or write code that run when selected a correct value
} else {
$scope.inputValid=false;
}};
Second part: typeahead-select-on-blur="true"// it's necessary since it first will make $scope.selected=selected value from dropdown (complete word) but also a bit weird, but important to know that after typeahead will selected your value it will run ng-blur= "checkSelectedValue()" directive in the end so there it will always check for validation and will set your $scope.inputValid=true or false depending on $scope.selected value.
I have an MVC App and on one of my pages as part of the display I will render one of two partials based on a user selection of a radio button. This bit all works ok, but I have a button on the main form where I need to set/reset values that will be passed to my controller based on the user selection. The button is declared on my main form as:
#Html.GlobalModalAuthorizeButton("Upload Document", "Upload", "Documents", new { serviceUserId = Model.ServiceUser.Id, folderId = Model.CurrentFolderId, viewType = Model.ViewTypes.ToString() }, new { #class = "icon upload btn-primary" })
when this page is initially rendered the viewtype is set to the default view that the user is initially presented with. when the user changes the view the viewtype doesn't seem to get updated. So from the partial that has been loaded I try to set the value to the correct value. Using the Chrome browsers Developer tools if I do the following:
$(this).parent().parent().parent().parent().find($('.upload')).attr('data-url').replace('FileView', 'TreeView');
it returns in the console window the value I want (idea is that i set the value on the button before the user presses it). The trouble is the above doesn't really seem to have changed the data-url attribute on the button so consequently when the controller is hit, 'FileView' is still passed through.
For full attribute:
var new_attr = "/ServiceUser/Documents/Upload?serviceUserId=21&viewType=FileView";
$(this).parent().parent().parent().parent().find($('.upload')).attr('data-url', new_attr);
Or, as #Rup already suggested, you should first get the original attribute value, modify that using replace method and then reassign the new_attr.
jQuery got a special method to read and write data attributes:
var uploadButton = $(this).parent().parent().parent().parent().find('.upload');
var currentUrl = uploadButton.data('url');
uploadButton.data('url', currentUrl.replace('FileView', 'TreeView'));
So I have a list of schedules that I need to display for a user and show which schedules he or she is currently on and give them the possibility to jump on and off said schedules.
My viewmodel looks like this
self = this;
self.shifts = ko.observableArray();
self.selectedShifts = ko.observableArray();
//I populate self.shifts here with a WEB API call
//Run through each shift and check if current user is on it and set checked / not checked value for checkbox
ko.utils.arrayForEach(self.shifts(), function(shift) {
//Clear array
self.usersOnShift([]);
//Populate array with all users on the shift
self.usersOnShift = ko.observableArray(WEB API CALL HERE);
var userInShift = ko.utils.arrayFirst(self.usersOnShift(), function(user) {
if (selectedUserId == user.ID) {
return true;
}
});
if (userInShift) {
self.selectedShifts.push(shift.ID);
}
});
ko.applyBindings(self);
My HTML looks like this
<div class="simple_overlay" id="shiftOverlay">
<div class="details">
<div data-bind="foreach: shifts">
<div><span class="staff-initials" data-bind="text:wardName"> </span><input type="checkbox" data-bind="value: ID, checked: $root.selectedShifts"/> </div>
</div>
<div>
Connect
Close
</div>
</div>
</div>
I can see that the value of the checkboxes are set correctly to the ID of the corresponding shifts. However a shift that I know the user in question is on is not checked and I know that the selectedShifts observableArray contains the value.
Somehow the "checked: $root.selectedShifts" call / check is not working but I know that it contains the right value. What am I doing wrong?
The problem is that your value is an integer, but when bound to the checkbox element, it becomes a string. When the checked binding tries to find the value in the array, it doesn't find a match because it uses strict equality for comparison and (2 === "2") is false.
The simplest way to work around this problem is to convert your values to string when you add them to the array:
self.selectedShifts.push("" + shift.ID);
Of course this means that your model has to change, and that might not be a great solution. I came up with a custom binding, checkedInArray that replaces checked and supports any type of value. You can learn about it, see it in action, and use it like this:
<input type="checkbox" data-bind="checkedInArray: {value: ID, array: $root.selectedShifts }" />
In Knockout 2.3.0 (which is still in development) there will be a new binding, checkedValue, that will allow you use any type of value with the checked binding. Using that version, you could update your HTML to use checkedValue:
<input type="checkbox" data-bind="checkedValue: ID, checked: $root.selectedShifts"/>
Is shift.ID an observable property? If it is, then you need to add it to the array like this:
self.selectedShifts.push(shift.ID());
Otherwise you're just adding the whole observable to the array, and not the value.