Reset `ObservableObject` properties after logout - swiftui

I have one ObservableObject class for managing login data:
final class LoginData: ObservableObject {
// MARK: - Properties
#Published var otpVerificationType: OTPVerificationType = .mobileNumber
#Published var firstName: String = ""
#Published var mobileNumber: String = ""
#Published var email: String = ""
}
Once I logout the app, my firstName, email, mobileNumber are filled up. How can I reset my LoginData properties' value to empty?

struct LoginInfo {
var otpVerificationType: OTPVerificationType
var firstName: String
var mobileNumber: String
var email: String
init(otpVerificationType: OTPVerificationType = .mobileNumber, firstName: String = "", mobileNumber: String = "", email: String = "") {
self.otpVerificationType = otpVerificationType
self.firstName = firstName
self.mobileNumber = mobileNumber
self.email = email
}
}
final class LoginData: ObservableObject {
// MARK: - Properties
#Published var loginInfo: LoginInfo?
// MARK: - setInfo
func setInfo(_ info: LoginInfo) {
loginInfo = info
}
// MARK: - resetInfo
func resetInfo() {
loginInfo = LoginInfo()
}
}
Then you can reset the info just by triggering the method:
#ObservedObject var loginData = LoginData()
let info = LoginInfo(firstName: "John", mobileNumber: "01XXXXXXXXX")
loginData.setInfo(info)
loginData.resetInfo()

Related

In SwiftUI, how do you filter a list on a subview when passing data through a NavigationLink?

I am new to SwiftUI and programming in general. I am trying to pass data and create navigation between different views in my app.
For my data model, I am using MVVM format even though my data is entirely static right now. I have two data models that I am trying to connect via enumeration: CategoryModel and SubCategoryModel (see below).
CategoryModel:
import Foundation
import SwiftUI
enum Category: String, CaseIterable, Identifiable {
var id: String { self.rawValue }
case explicit = "Explicit"
case adventure = "Adventure"
case artists = "Artists"
case holidays = "Holidays"
case movies = "Movies"
case people = "People"
case tasks = "Tasks"
case feelings = "Feelings"
case lifestyle = "Lifesytle"
case party = "Party"
case sports = "Sports"
}
//Root data -> set up data structure
//make Identifiable for ForEach looping in other views
struct CategoryModel: Identifiable {
let id = UUID().uuidString
let category: Category
let categoryTitle: String
let description: String
let isPurchase: Bool
let categoryImage: Image
}
class CategoryViewModel: ObservableObject {
#Published var gameCategories: [CategoryModel] = CategoryModel.all
#Published var filteredPurchase: [CategoryModel] = []
init() {
filterByPurchase()
}
func filterByPurchase() {
filteredPurchase = gameCategories.filter({ $0.isPurchase })
}
}
extension CategoryModel {
static let all = [
CategoryModel(
category: .explicit,
categoryTitle: "Adults Only",
description: "For those spicy, intimate moments.",
isPurchase: true,
categoryImage: Image(uiImage: #imageLiteral(resourceName: "Explicit"))
),
CategoryModel(
category: .adventure,
categoryTitle: "Call of the Wild",
description: "[Insert description here]",
isPurchase: false,
categoryImage: Image(uiImage: #imageLiteral(resourceName: "Adventure"))
),
CategoryModel(
category: .artists,
categoryTitle: "By the Artist",
description: "[Insert description here]",
isPurchase: false,
categoryImage: Image(uiImage: #imageLiteral(resourceName: "Artists"))
),
]
}
SubCategoryModel:
import Foundation
import SwiftUI
//Root data -> set up data structure
//make Identifiable for ForEach looping in other views
struct SubCategoryModel: Identifiable {
let id = UUID().uuidString
let category: Category
let subcategory: String
let subtitle: String
let subdescription: String
let instruction: String
let cardImage: Image
}
class SubCategoryViewModel: ObservableObject {
#Published var gameSubCategories: [SubCategoryModel] = SubCategoryModel.allSubs
#Published var filteredCategory: [SubCategoryModel] = []
#Published var categoryType: Category = .explicit
init() {
filterByCategory()
}
func filterByCategory() {
DispatchQueue.global(qos: .userInteractive).async {
let results = self.gameSubCategories
.lazy
.filter { item in
return item.category == self.categoryType
}
DispatchQueue.main.async {
self.filteredCategory = results.compactMap({ item in
return item
})
}
}
}
}
extension SubCategoryModel {
static let allSubs = [
SubCategoryModel(
category: .explicit,
subcategory: "Significant Other",
subtitle: "Bedroom Eyes",
subdescription: "[Insert sub-description here]",
instruction: "Instructions:\n \n1) Each player pick a song\n2) Be funny, genuine, or a maverick\n3) Enjoy the trip down memory lane",
cardImage: Image(uiImage: #imageLiteral(resourceName: "Explicit"))
),
SubCategoryModel(
category: .explicit,
subcategory: "Dating",
subtitle: "First Date",
subdescription: "[Insert sub-description here]",
instruction: "Instructions:\n \n1) Each player pick a song\n2) Be funny, genuine, or a maverick\n3) Enjoy the trip down memory lane",
cardImage: Image(uiImage: #imageLiteral(resourceName: "Explicit"))
),
SubCategoryModel(
category: .adventure,
subcategory: "Hiking",
subtitle: "Bedroom Eyes",
subdescription: "[Insert sub-description here]",
instruction: "Instructions:\n \n1) Each player pick a song\n2) Be funny, genuine, or a maverick\n3) Enjoy the trip down memory lane",
cardImage: Image(uiImage: #imageLiteral(resourceName: "Adventure"))
),
]
}
My goal is to click on a card from the CategoryView screen and navigate to the SubCategoryView via a navigation link. I want the SubCategoryView to show a filtered list of subcategories based on the category selected on the CategoryView screen.
CategoryView to SubCategoryView GIF
CategoryLoop code snippet:
struct CategoryLoop: View {
let categories: [CategoryModel]
var body: some View {
ZStack {
ScrollView {
VStack {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 150), spacing: 20)], spacing: 20) {
ForEach(categories) { item in
NavigationLink(destination: SubCategoryView()
.navigationTitle(item.category.rawValue)) {
CategoryCard(category: item)
}
}
}
Based on the code in my CategoryLoop file, what is the best/easiest way to pass my model data and filter the list on the SubCategoryView? I am having trouble figuring out how to use the enumeration. Is it possible to write a function that would update #Published var categoryType: Category = .explicit (see SubCategoryModel) based on the card clicked in the LazyVGrid? Also, if you have suggestion on how to better organise my data models, please let me know.

How to solve the error: "Cannot use mutating member on immutable value: 'users' is a get-only property" in xcode12 & swiftui

I'm getting the above error when I try to append to one of my arrays in my profile model.
Here is my profile model code:
import Foundation
struct UserProfile: Codable {
var firstName: String
var lastName: String
var age: Int16
var password: String
var email: String
}
extension UserProfile {
static var users: [UserProfile] {
[
UserProfile(firstName: "aryan", lastName: "chordia", age: 21, password: "123", email: "aryanchordia#gmail.com"),
UserProfile(firstName: "tyler", lastName: "duic", age: 21, password: "123", email: "tduic#andrew.cmu.edu"),
]
}
}
extension UserProfile {
struct Data {
var firstName: String = ""
var lastName: String = ""
var age: Int16 = 21
var password: String = ""
var email: String = ""
}
var data: Data {
return Data(firstName: firstName, lastName: lastName, age: age, password: password, email: email)
}
}
Here is how I try to append to my UserProfile.users array in SignUpView.swift
func signup() -> Bool {
let user = UserProfile(firstName: userData.firstName, lastName: userData.lastName, age: 21, password: userData.password, email: userData.email)
UserProfile.users.append(user)
return true
}
Any help greatly appreciated thanks!
You are using computed property here. Hence, the value is computed and you can not set it.
You can create your array with a function like that or declare is immediately with the correct value:
static var users: [UserProfile] = {
[
UserProfile(firstName: "aryan", lastName: "chordia", age: 21, password: "123", email: "aryanchordia#gmail.com"),
UserProfile(firstName: "tyler", lastName: "duic", age: 21, password: "123", email: "tduic#andrew.cmu.edu"),
]
}()

Get multiple list items by ID in SharePoint List

I am trying to retrieve a list items from a SharePoint list but my issue is that I would like to retrieve the last four items by ID and I don't know how to proceed using JSOM.
Can someone help me whit some CAML code on how to do that?
var ctx = new SP.ClientContext.get_current();
var web = ctx.get_web();
//Geting reference to the list
var olist = web.get_lists().getByTitle('Configs');
var oitem = olist.getItemById(1);
//get Title,id,ConfigItem fields
ctx.load(oitem, "Title", "Id", "ConfigItem");
ctx.executeQueryAsync(function () {
alert(oitem.get_item("Title"));
alert(oitem.get_item("ConfigItem"));
}, function (a, b) {
alert(b.get_message());
});
You could use rest api with order by and $top option for this requirement.
/_api/web/lists/getbytitle('chart')/items?$select=ID,Title&$orderby= ID desc&$top=4
Rest api get list items.
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('chart')/items?$select=ID,Title&$orderby= ID desc&$top=4",
type: "GET",
headers:
{
"Accept": "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose"
},
success: function (data) {
for (var i = 0; i < data.d.results.length; i++) {
var item = data.d.results[i];
//to do
}
},
error: function (data) {
console.log(data.responseJSON.error);
}
});
Here is JSOM solution with use of CamlQuery.
var ctx = new SP.ClientContext.get_current();
var web = ctx.get_web();
var query = new SP.CamlQuery()
query.set_viewXml("<View><Query><OrderBy><FieldRef Name='ID' Ascending='FALSE' /></OrderBy></Query><RowLimit>4</RowLimit></View>")
var list = web.get_lists().getByTitle('Configs');
var items = list.getItems(query, "ID", "Title", "FirstName", "LastName", "Level", "Grade", "Date");
var dictionary = [];
ctx.load(items);
ctx.executeQueryAsync(function () {
var enumerator = items.getEnumerator();
while (enumerator.moveNext()) {
var item = enumerator.get_current();
dictionary.push({
title: item.get_item("Title"),
firstName: item.get_item("FirstName"),
lastName: item.get_item("LastName"),
level: item.get_item("Level"),
grade: item.get_item("Grade"),
date: item.get_item("Date"),
});
}
}, function (a, b) {
alert(b.get_message());
});

google maps marker load via ajax and infocontent

In my app I have a google map and I want to add many marker on it and so I load the data via ajax (I'm in Django). I have the probem with infocontent and the 'click' event on the marker load via ajax: When I do 'click' on the marker nothing happened. This is my code:
function initialize() {
var latlng = new google.maps.LatLng({{lat}}, {{long}});
var myOptions = {
zoom: 16,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("mapCanvas"), myOptions);
var contentString = '<div id="content">{{name}}<br><span style="font-size:10px;">{{road}}</span><br><span style="font-size:10px;">{{city}} ({{prov}})</span></div>';
var infowindow_strutt = new google.maps.InfoWindow({
content: contentString
});
var marker = new google.maps.Marker({
position: latlng,
map: map,
title: '{{name}}'
});
google.maps.event.addListener(marker, 'click', function() {
infowindow_strutt.open(map,marker);
});
var markers = [];
var markers_strutt = [];
var markers_concor = [];
var icon_strutt = {
url: 'http://icons.iconarchive.com/icons/graphicloads/colorful-long-shadow/24/Home-icon.png'
};
var icon_concor = {
url: 'http://icons.iconarchive.com/icons/graphicloads/100-flat/24/home-icon.png'
};
var marker_concor
var marker_strutt
map.addListener('bounds_changed', function() {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
var bounds = map.getBounds();
var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();
$.ajax({
url: '/api/get_marker/',
cache: false,
data: {
'fromlat': southWest.lat(),
'tolat': northEast.lat(),
'fromlng': southWest.lng(),
'tolng': northEast.lng()
},
dataType: 'json',
type: 'GET',
async: false,
success: function (data) {
if (data) {
$.each(data, function (i, item) {
if (item.type = 1) {
var marker_concor = new google.maps.Marker({
position: new google.maps.LatLng(item.lat, item.lng),
icon: icon_concor,
map: map,
draggable: false
});
} else if (item.type = 2) {
var marker_strutt = new google.maps.Marker({
position: new google.maps.LatLng(item.lat, item.lng),
icon: icon_strutt,
map: map,
draggable: false
});
//Create an infoWindow
var infowindow_strutt = new google.maps.InfoWindow();
//set the content of infoWindow (the name)
infowindow_strutt.setContent(item.name);
//add click listner to marker which will open infoWindow
map.addListener(marker_strutt, 'click', function() {
infowindow_strutt.open(marker_strutt); // click on marker opens info window
});
}
markers_concor.push(marker_concor);
markers_strutt.push(marker_strutt);
if (marker_strutt) {
marker_strutt.setMap(map);
}
if (marker_concor) {
marker_concor.setMap(map);
}
});
}
}
});
});
}
jQuery(document).ready(function(e) {
initialize();
});
Where is the issue? Thanks a lot
EDIT: View code
def view_get_marker(request):
id = 24
list_id = []
list_marker = []
list_id.append(id)
# type 1 data
A_list = tab_A.objects.filter(id_struttura=id).filter(lat__gt=request.GET.get('fromlat'), lat__lt=request.GET.get('tolat')).filter(lng__gt=request.GET.get('fromlng'), lng__lt=request.GET.get('tolng'))
for a in A_list:
list_marker.append([a.lat, a.lng, a.name, a.road, a.city, a.id, 1])
list_id.append(a.id)
# type 2 data
B_list = list(tab_B.objects.all().values_list('lat','lng','name','road','city','id').exclude(lng__isnull=True).exclude(id__in=lista_id).filter(lat__gt=request.GET.get('fromlat'), lat__lt=request.GET.get('tolat')).filter(lng__gt=request.GET.get('fromlng'), lng__lt=request.GET.get('tolng')))
for lat, lng, name, road, city, id in B_list:
list_marker.append([lat, lng, name, road, city, id, 2])
if request.is_ajax():
results = []
for row in list_marker:
h_json = {}
h_json['lat'] = row[0]
h_json['lng'] = row[1]
h_json['name'] = unicode(row[2])
h_json['road'] = unicode(row[3])
h_json['city'] = unicode(row[4])
h_json['id'] = row[5]
h_json['type'] = row[6]
results.append(h_json)
data = json.dumps(results)
else:
data = 'fail'
mimetype = 'application/json'
return HttpResponse(data, mimetype)
EDIT 2:
I found the solution. The problem was in the event 'click' declaration. The right way is this:
google.maps.event.addListener(marker_strutt, 'click', (function(marker_strutt, i) {
return function() {
infowindow.setContent('my content');
infowindow.open(map, marker_strutt);
}
})(marker_strutt, i));
In this way I have the popoup!

Mark list item as viewed/read in SharePoint 2013

When a user views an item in SharePoint list, I need to capture that it has been viewed and who viewed the item (in additional columns). Is there a way to do that?
I did this by adding a script editor web part and inserting this script in there:
<script type="text/javascript" src="/jquery-1.10.2.min.js"></script>
<script src="/jquery.SPServices-2013.02a.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () { ExecuteOrDelayUntilScriptLoaded(loadConstants, "sp.js"); });
function loadConstants() {
var userid= _spPageContextInfo.userId;
var requestUri = _spPageContextInfo.webAbsoluteUrl + "/_api/web/getuserbyid(" + userid + ")";
var requestHeaders = { "accept" : "application/json;odata=verbose" };
$.ajax({
url : requestUri,
contentType : "application/json;odata=verbose",
headers : requestHeaders,
success : onSuccess,
error : onError
});
function onSuccess(data, request){
var loginName = data.d.Title;
var docurl = document.URL;
var beginindex = docurl.indexOf('?ID=') + 4;
var endindex = docurl.indexOf('&Source=');
var itemid = docurl.substring(beginindex, endindex);
var ctx = new SP.ClientContext("your website url");
var oList = ctx.get_web().get_lists().getByTitle('your library name');
this.oListItem = oList.getItemById(itemid);
this.oListItem.set_item('Read', loginName + ' ' + getTodayDate());
this.oListItem.update();
ctx.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
function onError(error) {
alert("error");
}
function getTodayDate() {
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth()+1; //January is 0!
var yyyy = today.getFullYear();
if(dd<10){dd='0'+dd} if(mm<10){mm='0'+mm} today = mm+'/'+dd+'/'+yyyy;
return today;
}
}
</script>